file_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. package burndown
  2. import (
  3. "fmt"
  4. "math"
  5. "testing"
  6. "github.com/stretchr/testify/assert"
  7. "gopkg.in/src-d/hercules.v6/internal/rbtree"
  8. )
  9. func updateStatusFile(status map[int]int64, _, previousTime, delta int) {
  10. status[previousTime] += int64(delta)
  11. }
  12. func fixtureFile() (*File, map[int]int64, *rbtree.Allocator) {
  13. status := map[int]int64{}
  14. alloc := rbtree.NewAllocator()
  15. file := NewFile(0, 100, alloc, func(a, b, c int) {
  16. updateStatusFile(status, a, b, c)
  17. })
  18. return file, status, alloc
  19. }
  20. func TestInitializeFile(t *testing.T) {
  21. file, status, _ := fixtureFile()
  22. dump := file.Dump()
  23. // Output:
  24. // 0 0
  25. // 100 -1
  26. assert.Equal(t, "0 0\n100 -1\n", dump)
  27. assert.Equal(t, int64(100), status[0])
  28. }
  29. func testPanicFile(t *testing.T, method func(*File), msg string) {
  30. defer func() {
  31. r := recover()
  32. assert.NotNil(t, r, "not panic()-ed")
  33. assert.IsType(t, "", r)
  34. assert.Contains(t, r.(string), msg)
  35. }()
  36. file, _, _ := fixtureFile()
  37. method(file)
  38. }
  39. func TestBullshitFile(t *testing.T) {
  40. testPanicFile(t, func(file *File) { file.Update(1, -10, 10, 0) }, "insert")
  41. testPanicFile(t, func(file *File) { file.Update(1, 110, 10, 0) }, "insert")
  42. testPanicFile(t, func(file *File) { file.Update(1, -10, 0, 10) }, "delete")
  43. testPanicFile(t, func(file *File) { file.Update(1, 100, 0, 10) }, "delete")
  44. testPanicFile(t, func(file *File) { file.Update(1, 0, -10, 0) }, "Length")
  45. testPanicFile(t, func(file *File) { file.Update(1, 0, 0, -10) }, "Length")
  46. testPanicFile(t, func(file *File) { file.Update(1, 0, -10, -10) }, "Length")
  47. testPanicFile(t, func(file *File) { file.Update(-1, 0, 10, 10) }, "time")
  48. file, status, alloc := fixtureFile()
  49. file.Update(1, 10, 0, 0)
  50. assert.Equal(t, int64(100), status[0])
  51. assert.Equal(t, int64(0), status[1])
  52. assert.Equal(t, alloc.Size(), 3) // 1 + 2 nodes
  53. }
  54. func TestCloneFile(t *testing.T) {
  55. file, status, alloc := fixtureFile()
  56. // 0 0 | 100 -1 [0]: 100
  57. file.Update(1, 20, 30, 0)
  58. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  59. file.Update(2, 20, 0, 5)
  60. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  61. file.Update(3, 20, 0, 5)
  62. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  63. file.Update(4, 20, 10, 0)
  64. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  65. assert.Equal(t, alloc.Size(), 6)
  66. clone := file.Clone(alloc.Clone())
  67. clone.Update(5, 45, 0, 10)
  68. // 0 0 | 20 4 | 30 1 | 45 0 | 120 -1 [0]: 95, [1]: 15, [4]: 10
  69. clone.Update(6, 45, 5, 0)
  70. // 0 0 | 20 4 | 30 1 | 45 6 | 50 0 | 125 -1 [0]: 95, [1]: 15, [4]: 10, [6]: 5
  71. assert.Equal(t, int64(95), status[0])
  72. assert.Equal(t, int64(15), status[1])
  73. assert.Equal(t, int64(0), status[2])
  74. assert.Equal(t, int64(0), status[3])
  75. assert.Equal(t, int64(10), status[4])
  76. assert.Equal(t, int64(0), status[5])
  77. assert.Equal(t, int64(5), status[6])
  78. dump := file.Dump()
  79. // Output:
  80. // 0 0
  81. // 20 4
  82. // 30 1
  83. // 50 0
  84. // 130 -1
  85. assert.Equal(t, "0 0\n20 4\n30 1\n50 0\n130 -1\n", dump)
  86. dump = clone.Dump()
  87. // Output:
  88. // 0 0
  89. // 20 4
  90. // 30 1
  91. // 45 6
  92. // 50 0
  93. // 125 -1
  94. assert.Equal(t, "0 0\n20 4\n30 1\n45 6\n50 0\n125 -1\n", dump)
  95. }
  96. func TestLenFile(t *testing.T) {
  97. file, _, _ := fixtureFile()
  98. assert.Equal(t, 100, file.Len())
  99. }
  100. func TestInsertFile(t *testing.T) {
  101. file, status, _ := fixtureFile()
  102. file.Update(1, 10, 10, 0)
  103. dump := file.Dump()
  104. // Output:
  105. // 0 0
  106. // 10 1
  107. // 20 0
  108. // 110 -1
  109. assert.Equal(t, "0 0\n10 1\n20 0\n110 -1\n", dump)
  110. assert.Equal(t, int64(100), status[0])
  111. assert.Equal(t, int64(10), status[1])
  112. }
  113. func TestZeroInitializeFile(t *testing.T) {
  114. status := map[int]int64{}
  115. file := NewFile(0, 0, rbtree.NewAllocator(), func(a, b, c int) {
  116. updateStatusFile(status, a, b, c)
  117. })
  118. assert.Contains(t, status, 0)
  119. dump := file.Dump()
  120. // Output:
  121. // 0 -1
  122. assert.Equal(t, "0 -1\n", dump)
  123. file.Update(1, 0, 10, 0)
  124. dump = file.Dump()
  125. // Output:
  126. // 0 1
  127. // 10 -1
  128. assert.Equal(t, "0 1\n10 -1\n", dump)
  129. assert.Equal(t, int64(10), status[1])
  130. }
  131. func TestDeleteFile(t *testing.T) {
  132. file, status, alloc := fixtureFile()
  133. file.Update(1, 10, 0, 10)
  134. dump := file.Dump()
  135. // Output:
  136. // 0 0
  137. // 90 -1
  138. assert.Equal(t, "0 0\n90 -1\n", dump)
  139. assert.Equal(t, int64(90), status[0])
  140. assert.Equal(t, int64(0), status[1])
  141. assert.Equal(t, alloc.Size(), 3)
  142. }
  143. func TestFusedFile(t *testing.T) {
  144. file, status, alloc := fixtureFile()
  145. file.Update(1, 10, 6, 7)
  146. dump := file.Dump()
  147. // Output:
  148. // 0 0
  149. // 10 1
  150. // 16 0
  151. // 99 -1
  152. assert.Equal(t, "0 0\n10 1\n16 0\n99 -1\n", dump)
  153. assert.Equal(t, int64(93), status[0])
  154. assert.Equal(t, int64(6), status[1])
  155. file.Update(3, 10, 0, 6)
  156. dump = file.Dump()
  157. assert.Equal(t, "0 0\n93 -1\n", dump)
  158. assert.Equal(t, alloc.Size(), 5)
  159. file.Update(3, 10, 6, 0) // +2 nodes
  160. assert.Equal(t, alloc.Size(), 5) // using gaps
  161. file.Update(4, 10, 6, 0)
  162. assert.Equal(t, alloc.Size(), 6)
  163. }
  164. func TestDeleteSameBeginning(t *testing.T) {
  165. file, _, _ := fixtureFile()
  166. file.Update(1, 0, 5, 0)
  167. dump := file.Dump()
  168. // Output:
  169. // 0 0
  170. // 10 1
  171. // 16 0
  172. // 99 -1
  173. assert.Equal(t, "0 1\n5 0\n105 -1\n", dump)
  174. file.Update(3, 0, 0, 5)
  175. dump = file.Dump()
  176. assert.Equal(t, "0 0\n100 -1\n", dump)
  177. }
  178. func TestInsertSameTimeFile(t *testing.T) {
  179. file, status, _ := fixtureFile()
  180. file.Update(0, 5, 10, 0)
  181. dump := file.Dump()
  182. // Output:
  183. // 0 0
  184. // 110 -1
  185. assert.Equal(t, "0 0\n110 -1\n", dump)
  186. assert.Equal(t, int64(110), status[0])
  187. }
  188. func TestInsertSameStartFile(t *testing.T) {
  189. file, status, _ := fixtureFile()
  190. file.Update(1, 10, 10, 0)
  191. file.Update(2, 10, 10, 0)
  192. dump := file.Dump()
  193. // Output:
  194. // 0 0
  195. // 10 2
  196. // 20 1
  197. // 30 0
  198. // 120 -1
  199. assert.Equal(t, "0 0\n10 2\n20 1\n30 0\n120 -1\n", dump)
  200. assert.Equal(t, int64(100), status[0])
  201. assert.Equal(t, int64(10), status[1])
  202. assert.Equal(t, int64(10), status[2])
  203. }
  204. func TestInsertEndFile(t *testing.T) {
  205. file, status, _ := fixtureFile()
  206. file.Update(1, 100, 10, 0)
  207. dump := file.Dump()
  208. // Output:
  209. // 0 0
  210. // 100 1
  211. // 110 -1
  212. assert.Equal(t, "0 0\n100 1\n110 -1\n", dump)
  213. assert.Equal(t, int64(100), status[0])
  214. assert.Equal(t, int64(10), status[1])
  215. }
  216. func TestDeleteSameStart0File(t *testing.T) {
  217. file, status, _ := fixtureFile()
  218. file.Update(1, 0, 0, 10)
  219. dump := file.Dump()
  220. // Output:
  221. // 0 0
  222. // 90 -1
  223. assert.Equal(t, "0 0\n90 -1\n", dump)
  224. assert.Equal(t, int64(90), status[0])
  225. assert.Equal(t, int64(0), status[1])
  226. }
  227. func TestDeleteSameStartMiddleFile(t *testing.T) {
  228. file, status, _ := fixtureFile()
  229. file.Update(1, 10, 10, 0)
  230. file.Update(2, 10, 0, 5)
  231. dump := file.Dump()
  232. // Output:
  233. // 0 0
  234. // 10 1
  235. // 15 0
  236. // 105 -1
  237. assert.Equal(t, "0 0\n10 1\n15 0\n105 -1\n", dump)
  238. assert.Equal(t, int64(100), status[0])
  239. assert.Equal(t, int64(5), status[1])
  240. }
  241. func TestDeleteIntersectionFile(t *testing.T) {
  242. file, status, _ := fixtureFile()
  243. file.Update(1, 10, 10, 0)
  244. file.Update(2, 15, 0, 10)
  245. dump := file.Dump()
  246. // Output:
  247. // 0 0
  248. // 10 1
  249. // 15 0
  250. // 100 -1
  251. assert.Equal(t, "0 0\n10 1\n15 0\n100 -1\n", dump)
  252. assert.Equal(t, int64(95), status[0])
  253. assert.Equal(t, int64(5), status[1])
  254. }
  255. func TestDeleteAllFile(t *testing.T) {
  256. file, status, _ := fixtureFile()
  257. file.Update(1, 0, 0, 100)
  258. // Output:
  259. // 0 -1
  260. dump := file.Dump()
  261. assert.Equal(t, "0 -1\n", dump)
  262. assert.Equal(t, int64(0), status[0])
  263. assert.Equal(t, int64(0), status[1])
  264. }
  265. func TestFusedIntersectionFile(t *testing.T) {
  266. file, status, _ := fixtureFile()
  267. file.Update(1, 10, 10, 0)
  268. file.Update(2, 15, 3, 10)
  269. dump := file.Dump()
  270. // Output:
  271. // 0 0
  272. // 10 1
  273. // 15 2
  274. // 18 0
  275. // 103 -1
  276. assert.Equal(t, "0 0\n10 1\n15 2\n18 0\n103 -1\n", dump)
  277. assert.Equal(t, int64(95), status[0])
  278. assert.Equal(t, int64(5), status[1])
  279. assert.Equal(t, int64(3), status[2])
  280. }
  281. func TestTortureFile(t *testing.T) {
  282. file, status, _ := fixtureFile()
  283. // 0 0 | 100 -1 [0]: 100
  284. file.Update(1, 20, 30, 0)
  285. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  286. file.Update(2, 20, 0, 5)
  287. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  288. file.Update(3, 20, 0, 5)
  289. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  290. file.Update(4, 20, 10, 0)
  291. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  292. file.Update(5, 45, 0, 10)
  293. // 0 0 | 20 4 | 30 1 | 45 0 | 120 -1 [0]: 95, [1]: 15, [4]: 10
  294. file.Update(6, 45, 5, 0)
  295. // 0 0 | 20 4 | 30 1 | 45 6 | 50 0 | 125 -1 [0]: 95, [1]: 15, [4]: 10, [6]: 5
  296. file.Update(7, 10, 0, 50)
  297. // 0 0 | 75 -1 [0]: 75
  298. file.Update(8, 0, 10, 10)
  299. // 0 8 | 10 0 | 75 -1 [0]: 65, [8]: 10
  300. dump := file.Dump()
  301. assert.Equal(t, "0 8\n10 0\n75 -1\n", dump)
  302. assert.Equal(t, int64(65), status[0])
  303. assert.Equal(t, int64(0), status[1])
  304. assert.Equal(t, int64(0), status[2])
  305. assert.Equal(t, int64(0), status[3])
  306. assert.Equal(t, int64(0), status[4])
  307. assert.Equal(t, int64(0), status[5])
  308. assert.Equal(t, int64(0), status[6])
  309. assert.Equal(t, int64(0), status[7])
  310. assert.Equal(t, int64(10), status[8])
  311. }
  312. func TestInsertDeleteSameTimeFile(t *testing.T) {
  313. file, status, _ := fixtureFile()
  314. file.Update(0, 10, 10, 20)
  315. dump := file.Dump()
  316. assert.Equal(t, "0 0\n90 -1\n", dump)
  317. assert.Equal(t, int64(90), status[0])
  318. file.Update(0, 10, 20, 10)
  319. dump = file.Dump()
  320. assert.Equal(t, "0 0\n100 -1\n", dump)
  321. assert.Equal(t, int64(100), status[0])
  322. }
  323. func TestBug1File(t *testing.T) {
  324. file, status, _ := fixtureFile()
  325. file.Update(316, 1, 86, 0)
  326. file.Update(316, 87, 0, 99)
  327. file.Update(251, 0, 1, 0)
  328. file.Update(251, 1, 0, 1)
  329. dump := file.Dump()
  330. assert.Equal(t, "0 251\n1 316\n87 -1\n", dump)
  331. assert.Equal(t, int64(1), status[251])
  332. assert.Equal(t, int64(86), status[316])
  333. file.Update(316, 0, 0, 1)
  334. file.Update(316, 0, 1, 0)
  335. dump = file.Dump()
  336. assert.Equal(t, "0 316\n87 -1\n", dump)
  337. assert.Equal(t, int64(0), status[251])
  338. assert.Equal(t, int64(87), status[316])
  339. }
  340. func TestBug2File(t *testing.T) {
  341. file, status, _ := fixtureFile()
  342. file.Update(316, 1, 86, 0)
  343. file.Update(316, 87, 0, 99)
  344. file.Update(251, 0, 1, 0)
  345. file.Update(251, 1, 0, 1)
  346. dump := file.Dump()
  347. assert.Equal(t, "0 251\n1 316\n87 -1\n", dump)
  348. file.Update(316, 0, 1, 1)
  349. dump = file.Dump()
  350. assert.Equal(t, "0 316\n87 -1\n", dump)
  351. assert.Equal(t, int64(0), status[251])
  352. assert.Equal(t, int64(87), status[316])
  353. }
  354. func TestJoinFile(t *testing.T) {
  355. file, status, _ := fixtureFile()
  356. file.Update(1, 10, 10, 0)
  357. file.Update(1, 30, 10, 0)
  358. file.Update(1, 20, 10, 10)
  359. dump := file.Dump()
  360. assert.Equal(t, "0 0\n10 1\n40 0\n120 -1\n", dump)
  361. assert.Equal(t, int64(90), status[0])
  362. assert.Equal(t, int64(30), status[1])
  363. }
  364. func TestBug3File(t *testing.T) {
  365. file, status, _ := fixtureFile()
  366. file.Update(0, 1, 0, 99)
  367. file.Update(0, 0, 1, 1)
  368. dump := file.Dump()
  369. assert.Equal(t, "0 0\n1 -1\n", dump)
  370. assert.Equal(t, int64(1), status[0])
  371. }
  372. func TestBug4File(t *testing.T) {
  373. status := map[int]int64{}
  374. file := NewFile(0, 10, rbtree.NewAllocator(), func(a, b, c int) {
  375. updateStatusFile(status, a, b, c)
  376. })
  377. // 0 0 | 10 -1
  378. file.Update(125, 0, 20, 9)
  379. // 0 125 | 20 0 | 21 -1
  380. file.Update(125, 0, 20, 20)
  381. // 0 125 | 20 0 | 21 -1
  382. file.Update(166, 12, 1, 1)
  383. // 0 125 | 12 166 | 13 125 | 20 0 | 21 -1
  384. file.Update(214, 2, 1, 1)
  385. // 0 125 | 2 214 | 3 125 | 12 166 | 13 125 | 20 0 | 21 -1
  386. file.Update(214, 4, 9, 0)
  387. // 0 125 | 2 214 | 3 125 | 4 214 | 13 125 | 21 166 | 22 125 | 29 0 | 30 -1
  388. file.Update(214, 27, 1, 1)
  389. // 0 125 | 2 214 | 3 125 | 4 214 | 13 125 | 21 166 | 22 125 | 27 214 | 28 125 | 29 0 | 30 -1
  390. file.Update(215, 3, 1, 1)
  391. // 0 125 | 2 214 | 3 215 | 4 214 | 13 125 | 21 166 | 22 125 | 27 214 | 28 125 | 29 0 | 30 -1
  392. file.Update(215, 13, 1, 1)
  393. // 0 125 | 2 214 | 3 215 | 4 214 | 13 215 | 14 125 | 21 166 | 22 125 | 27 214 | 28 125 | 29 0 | 30 -1
  394. file.Update(215, 17, 1, 1)
  395. // 0 125 | 2 214 | 3 215 | 4 214 | 13 215 | 14 125 | 17 215 | 18 125 | 21 166 | 22 125 | 27 214 | 28 125 | 29 0 | 30 -1
  396. file.Update(215, 19, 5, 0)
  397. // 0 125 | 2 214 | 3 215 | 4 214 | 13 215 | 14 125 | 17 215 | 18 125 | 19 215 | 24 125 | 26 166 | 27 125 | 32 214 | 33 125 | 34 0 | 35 -1
  398. file.Update(215, 25, 0, 1)
  399. // 0 125 | 2 214 | 3 215 | 4 214 | 13 215 | 14 125 | 17 215 | 18 125 | 19 215 | 24 125 | 25 166 | 26 125 | 31 214 | 32 125 | 33 0 | 34 -1
  400. file.Update(215, 31, 6, 1)
  401. // 0 125 | 2 214 | 3 215 | 4 214 | 13 215 | 14 125 | 17 215 | 18 125 | 19 215 | 24 125 | 25 166 | 26 125 | 31 215 | 37 125 | 38 0 | 39 -1
  402. file.Update(215, 27, 15, 0)
  403. // 0 125 | 2 214 | 3 215 | 4 214 | 13 215 | 14 125 | 17 215 | 18 125 | 19 215 | 24 125 | 25 166 | 26 125 | 27 215 | 42 125 | 46 215 | 52 125 | 53 0 | 54 -1
  404. file.Update(215, 2, 25, 4)
  405. // 0 125 | 2 215 | 27 214 | 34 215 | 35 125 | 38 215 | 39 125 | 40 215 | 45 125 | 46 166 | 47 125 | 48 215 | 63 125 | 67 215 | 73 125 | 74 0 | 75 -1
  406. file.Update(215, 28, 1, 1)
  407. // 0 125 | 2 215 | 27 214 | 28 215 | 29 214 | 34 215 | 35 125 | 38 215 | 39 125 | 40 215 | 45 125 | 46 166 | 47 125 | 48 215 | 63 125 | 67 215 | 73 125 | 74 0 | 75 -1
  408. file.Update(215, 30, 7, 2)
  409. // 0 125 | 2 215 | 27 214 | 28 215 | 29 214 | 30 215 | 37 214 | 39 215 | 40 125 | 43 215 | 44 125 | 45 215 | 50 125 | 51 166 | 52 125 | 53 215 | 68 125 | 72 215 | 78 125 | 79 0 | 80 -1
  410. file.Update(215, 38, 1, 0)
  411. // 0 125 | 2 215 | 27 214 | 28 215 | 29 214 | 30 215 | 37 214 | 38 215 | 39 214 | 40 215 | 41 125 | 44 215 | 45 125 | 46 215 | 51 125 | 52 166 | 53 125 | 54 215 | 69 125 | 73 215 | 79 125 | 80 0 | 81 -1
  412. file.Update(215, 40, 4, 2)
  413. // 0 125 | 2 215 | 27 214 | 28 215 | 29 214 | 30 215 | 37 214 | 38 215 | 39 214 | 40 215 | 44 125 | 46 215 | 47 125 | 48 215 | 53 125 | 54 166 | 55 125 | 56 215 | 71 125 | 75 215 | 81 125 | 82 0 | 83 -1
  414. file.Update(215, 46, 1, 0)
  415. // 0 125 | 2 215 | 27 214 | 28 215 | 29 214 | 30 215 | 37 214 | 38 215 | 39 214 | 40 215 | 44 125 | 46 215 | 48 125 | 49 215 | 54 125 | 55 166 | 56 125 | 57 215 | 72 125 | 76 215 | 82 125 | 83 0 | 84 -1
  416. file.Update(215, 49, 1, 0)
  417. // 0 125 | 2 215 | 27 214 | 28 215 | 29 214 | 30 215 | 37 214 | 38 215 | 39 214 | 40 215 | 44 125 | 46 215 | 48 125 | 49 215 | 55 125 | 56 166 | 57 125 | 58 215 | 73 125 | 77 215 | 83 125 | 84 0 | 85 -1
  418. file.Update(215, 52, 2, 6)
  419. // 0 125 | 2 215 | 27 214 | 28 215 | 29 214 | 30 215 | 37 214 | 38 215 | 39 214 | 40 215 | 44 125 | 46 215 | 48 125 | 49 215 | 69 125 | 73 215 | 79 125 | 80 0 | 81 -1
  420. dump := file.Dump()
  421. assert.Equal(t, "0 125\n2 215\n27 214\n28 215\n29 214\n30 215\n37 214\n38 215\n39 214\n40 215\n44 125\n46 215\n48 125\n49 215\n69 125\n73 215\n79 125\n80 0\n81 -1\n", dump)
  422. file.Update(214, 38, 1, 1)
  423. // 0 125 | 2 215 | 27 214 | 28 215 | 29 214 | 30 215 | 37 214 | 40 215 | 44 125 | 46 215 | 48 125 | 49 215 | 69 125 | 73 215 | 79 125 | 80 0 | 81 -1
  424. dump = file.Dump()
  425. assert.Equal(t, "0 125\n2 215\n27 214\n28 215\n29 214\n30 215\n37 214\n40 215\n44 125\n46 215\n48 125\n49 215\n69 125\n73 215\n79 125\n80 0\n81 -1\n", dump)
  426. file.Update(300, 28, 1, 1)
  427. // 0 125 | 2 215 | 27 214 | 28 300 | 29 214 | 30 215 | 37 214 | 40 215 | 44 125 | 46 215 | 48 125 | 49 215 | 69 125 | 73 215 | 79 125 | 80 0 | 81 -1
  428. dump = file.Dump()
  429. assert.Equal(t, "0 125\n2 215\n27 214\n28 300\n29 214\n30 215\n37 214\n40 215\n44 125\n46 215\n48 125\n49 215\n69 125\n73 215\n79 125\n80 0\n81 -1\n", dump)
  430. }
  431. func TestBug5File(t *testing.T) {
  432. status := map[int]int64{}
  433. keys := []int{0, 2, 4, 7, 10}
  434. vals := []int{24, 28, 24, 28, math.MaxUint32}
  435. file := NewFileFromTree(keys, vals, rbtree.NewAllocator(), func(a, b, c int) {
  436. updateStatusFile(status, a, b, c)
  437. })
  438. file.Update(28, 0, 1, 3)
  439. dump := file.Dump()
  440. assert.Equal(t, "0 28\n2 24\n5 28\n8 -1\n", dump)
  441. keys = []int{0, 1, 16, 18}
  442. vals = []int{305, 0, 157, math.MaxUint32}
  443. file = NewFileFromTree(keys, vals, rbtree.NewAllocator(), func(a, b, c int) {
  444. updateStatusFile(status, a, b, c)
  445. })
  446. file.Update(310, 0, 0, 2)
  447. dump = file.Dump()
  448. assert.Equal(t, "0 0\n14 157\n16 -1\n", dump)
  449. }
  450. func TestNewFileFromTreeInvalidSize(t *testing.T) {
  451. keys := [...]int{1, 2, 3}
  452. vals := [...]int{4, 5}
  453. assert.Panics(t, func() { NewFileFromTree(keys[:], vals[:], rbtree.NewAllocator()) })
  454. }
  455. func TestUpdatePanic(t *testing.T) {
  456. keys := [...]int{0}
  457. vals := [...]int{math.MaxUint32}
  458. file := NewFileFromTree(keys[:], vals[:], rbtree.NewAllocator())
  459. file.tree.DeleteWithKey(0)
  460. file.tree.Insert(rbtree.Item{Key: 1, Value: math.MaxUint32})
  461. assert.PanicsWithValue(t, "invalid tree state", func(){file.Update(1, 0, 1, 0)})
  462. file.tree.Insert(rbtree.Item{Key: 0, Value: math.MaxUint32})
  463. assert.PanicsWithValue(
  464. t, "time may not be >= MaxUint32", func(){file.Update(math.MaxUint32, 0, 1, 0)})
  465. }
  466. func TestFileValidate(t *testing.T) {
  467. keys := [...]int{0}
  468. vals := [...]int{math.MaxUint32}
  469. file := NewFileFromTree(keys[:], vals[:], rbtree.NewAllocator())
  470. file.tree.DeleteWithKey(0)
  471. file.tree.Insert(rbtree.Item{Key: 1, Value: math.MaxUint32})
  472. assert.Panics(t, func() { file.Validate() })
  473. file.tree.DeleteWithKey(1)
  474. file.tree.Insert(rbtree.Item{Key: 0, Value: math.MaxUint32})
  475. file.Validate()
  476. file.tree.DeleteWithKey(0)
  477. file.tree.Insert(rbtree.Item{Key: 0, Value: 0})
  478. assert.Panics(t, func() { file.Validate() })
  479. file.tree.DeleteWithKey(0)
  480. file.tree.Insert(rbtree.Item{Key: 0, Value: 1})
  481. file.tree.Insert(rbtree.Item{Key: 1, Value: 1})
  482. file.tree.Insert(rbtree.Item{Key: 2, Value: math.MaxUint32})
  483. file.Validate()
  484. file.tree.FindGE(2).Item().Key = 1
  485. assert.Panics(t, func() { file.Validate() })
  486. }
  487. func TestFileFlatten(t *testing.T) {
  488. file, _, _ := fixtureFile()
  489. // 0 0 | 100 -1 [0]: 100
  490. file.Update(1, 20, 30, 0)
  491. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  492. file.Update(2, 20, 0, 5)
  493. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  494. file.Update(3, 20, 0, 5)
  495. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  496. file.Update(4, 20, 10, 0)
  497. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  498. lines := file.flatten()
  499. for i := 0; i < 20; i++ {
  500. assert.Equal(t, 0, lines[i], fmt.Sprintf("line %d", i))
  501. }
  502. for i := 20; i < 30; i++ {
  503. assert.Equal(t, 4, lines[i], fmt.Sprintf("line %d", i))
  504. }
  505. for i := 30; i < 50; i++ {
  506. assert.Equal(t, 1, lines[i], fmt.Sprintf("line %d", i))
  507. }
  508. for i := 50; i < 130; i++ {
  509. assert.Equal(t, 0, lines[i], fmt.Sprintf("line %d", i))
  510. }
  511. assert.Len(t, lines, 130)
  512. }
  513. func TestFileMergeMark(t *testing.T) {
  514. file, status, _ := fixtureFile()
  515. // 0 0 | 100 -1 [0]: 100
  516. file.Update(1, 20, 30, 0)
  517. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  518. file.Update(2, 20, 0, 5)
  519. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  520. file.Update(3, 20, 0, 5)
  521. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  522. file.Update(4, 20, 10, 0)
  523. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  524. file.Update(TreeMergeMark, 60, 20, 20)
  525. // 0 0 | 20 4 | 30 1 | 50 0 | 60 M | 80 0 | 130 -1
  526. // [0]: 100, [1]: 20, [4]: 10
  527. dump := file.Dump()
  528. assert.Equal(t, "0 0\n20 4\n30 1\n50 0\n60 16383\n80 0\n130 -1\n", dump)
  529. assert.Contains(t, status, 0)
  530. assert.Equal(t, int64(100), status[0])
  531. assert.Equal(t, int64(20), status[1])
  532. assert.Equal(t, int64(0), status[2])
  533. assert.Equal(t, int64(0), status[3])
  534. assert.Equal(t, int64(10), status[4])
  535. assert.NotContains(t, status, TreeMergeMark)
  536. }
  537. func TestFileMerge(t *testing.T) {
  538. file1, status, alloc := fixtureFile()
  539. // 0 0 | 100 -1 [0]: 100
  540. file1.Update(1, 20, 30, 0)
  541. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  542. file1.Update(2, 20, 0, 5)
  543. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  544. file1.Update(3, 20, 0, 5)
  545. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  546. file1.Update(4, 20, 10, 0)
  547. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  548. file2 := file1.Clone(alloc.Clone())
  549. file1.Update(TreeMergeMark, 60, 30, 30)
  550. // 0 0 | 20 4 | 30 1 | 50 0 | 60 M | 90 0 | 130 -1
  551. // [0]: 70, [1]: 20, [4]: 10
  552. file2.Update(5, 60, 20, 20)
  553. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 0 | 130 -1
  554. // [0]: 80, [1]: 20, [4]: 10, [5]: 20
  555. file2.Update(TreeMergeMark, 80, 10, 10)
  556. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 M | 90 0 | 130 -1
  557. // [0]: 70, [1]: 20, [4]: 10, [5]: 20
  558. file2.Update(6, 0, 10, 10)
  559. // 0 6 | 10 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 M | 90 0 | 130 -1
  560. // [0]: 60, [1]: 20, [4]: 10, [5]: 20, [6]: 10
  561. file1.Merge(7, file2)
  562. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 7 | 90 0 | 130 -1
  563. // [0]: 70, [1]: 20, [4]: 10, [5]: 20, [6]: 0, [7]: 10
  564. dump := file1.Dump()
  565. assert.Equal(t, "0 0\n20 4\n30 1\n50 0\n60 5\n80 7\n90 0\n130 -1\n", dump)
  566. assert.Equal(t, int64(70), status[0])
  567. assert.Equal(t, int64(20), status[1])
  568. assert.Equal(t, int64(0), status[2])
  569. assert.Equal(t, int64(0), status[3])
  570. assert.Equal(t, int64(10), status[4])
  571. assert.Equal(t, int64(20), status[5])
  572. assert.Equal(t, int64(10), status[6])
  573. assert.Equal(t, int64(10), status[7])
  574. }
  575. func TestFileMergeNoop(t *testing.T) {
  576. file1, _, _ := fixtureFile()
  577. // 0 0 | 100 -1 [0]: 100
  578. assert.Panics(t, func() { file1.Merge(3, nil) })
  579. }
  580. func TestFileMergeNil(t *testing.T) {
  581. file, _, _ := fixtureFile()
  582. assert.Panics(t, func() {
  583. file.Merge(1, nil)
  584. })
  585. }
  586. func TestBug6File(t *testing.T) {
  587. status := map[int]int64{}
  588. keys := []int{0, 113, 153, 154}
  589. vals := []int{7, 10, 7, math.MaxUint32}
  590. file := NewFileFromTree(keys, vals, rbtree.NewAllocator(), func(a, b, c int) {
  591. updateStatusFile(status, a, b, c)
  592. })
  593. // 0 7 | 113 10 | 153 7 | 154 -1
  594. file.Update(10, 99, 1, 1)
  595. // 0 7 | 99 10 | 100 7 | 113 10 | 153 7 | 154 -1
  596. file.Update(10, 104, 1, 1)
  597. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 113 10 | 153 7 | 154 -1
  598. file.Update(10, 106, 1, 1)
  599. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 106 10 | 107 7 | 113 10 | 153 7 | 154 -1
  600. file.Update(10, 108, 1, 1)
  601. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 106 10 | 107 7 | 108 10 | 109 7 | 113 10 | 153 7 | 154 -1
  602. file.Update(10, 115, 2, 0)
  603. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 106 10 | 107 7 | 108 10 | 109 7 | 113 10 | 155 7 | 156 -1
  604. file.Update(10, 125, 4, 2)
  605. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 106 10 | 107 7 | 108 10 | 109 7 | 113 10 | 157 7 | 158 -1
  606. dump := file.Dump()
  607. assert.Equal(t, "0 7\n99 10\n100 7\n104 10\n105 7\n106 10\n107 7\n108 10\n109 7\n113 10\n157 7\n158 -1\n", dump)
  608. file = NewFileFromTree(keys, vals, rbtree.NewAllocator(), func(a, b, c int) {
  609. updateStatusFile(status, a, b, c)
  610. })
  611. // 0 7 | 113 10 | 153 7 | 154 -1
  612. file.Update(10, 112, 1, 1)
  613. // 0 7 | 112 10 | 153 7 | 154 -1
  614. dump = file.Dump()
  615. assert.Equal(t, "0 7\n112 10\n153 7\n154 -1\n", dump)
  616. }