file_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. package burndown
  2. import (
  3. "fmt"
  4. "math"
  5. "testing"
  6. "github.com/stretchr/testify/assert"
  7. "gopkg.in/src-d/hercules.v10/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 TestCloneFileShallow(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.CloneShallow(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 TestCloneFileDeep(t *testing.T) {
  97. file, status, alloc := fixtureFile()
  98. // 0 0 | 100 -1 [0]: 100
  99. file.Update(1, 20, 30, 0)
  100. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  101. file.Update(2, 20, 0, 5)
  102. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  103. file.Update(3, 20, 0, 5)
  104. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  105. file.Update(4, 20, 10, 0)
  106. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  107. assert.Equal(t, alloc.Size(), 6)
  108. clone := file.CloneDeep(rbtree.NewAllocator())
  109. clone.Update(5, 45, 0, 10)
  110. // 0 0 | 20 4 | 30 1 | 45 0 | 120 -1 [0]: 95, [1]: 15, [4]: 10
  111. clone.Update(6, 45, 5, 0)
  112. // 0 0 | 20 4 | 30 1 | 45 6 | 50 0 | 125 -1 [0]: 95, [1]: 15, [4]: 10, [6]: 5
  113. assert.Equal(t, int64(95), status[0])
  114. assert.Equal(t, int64(15), status[1])
  115. assert.Equal(t, int64(0), status[2])
  116. assert.Equal(t, int64(0), status[3])
  117. assert.Equal(t, int64(10), status[4])
  118. assert.Equal(t, int64(0), status[5])
  119. assert.Equal(t, int64(5), status[6])
  120. dump := file.Dump()
  121. // Output:
  122. // 0 0
  123. // 20 4
  124. // 30 1
  125. // 50 0
  126. // 130 -1
  127. assert.Equal(t, "0 0\n20 4\n30 1\n50 0\n130 -1\n", dump)
  128. dump = clone.Dump()
  129. // Output:
  130. // 0 0
  131. // 20 4
  132. // 30 1
  133. // 45 6
  134. // 50 0
  135. // 125 -1
  136. assert.Equal(t, "0 0\n20 4\n30 1\n45 6\n50 0\n125 -1\n", dump)
  137. }
  138. func TestLenFile(t *testing.T) {
  139. file, _, _ := fixtureFile()
  140. assert.Equal(t, 100, file.Len())
  141. }
  142. func TestInsertFile(t *testing.T) {
  143. file, status, _ := fixtureFile()
  144. file.Update(1, 10, 10, 0)
  145. dump := file.Dump()
  146. // Output:
  147. // 0 0
  148. // 10 1
  149. // 20 0
  150. // 110 -1
  151. assert.Equal(t, "0 0\n10 1\n20 0\n110 -1\n", dump)
  152. assert.Equal(t, int64(100), status[0])
  153. assert.Equal(t, int64(10), status[1])
  154. }
  155. func TestZeroInitializeFile(t *testing.T) {
  156. status := map[int]int64{}
  157. file := NewFile(0, 0, rbtree.NewAllocator(), func(a, b, c int) {
  158. updateStatusFile(status, a, b, c)
  159. })
  160. assert.Contains(t, status, 0)
  161. dump := file.Dump()
  162. // Output:
  163. // 0 -1
  164. assert.Equal(t, "0 -1\n", dump)
  165. file.Update(1, 0, 10, 0)
  166. dump = file.Dump()
  167. // Output:
  168. // 0 1
  169. // 10 -1
  170. assert.Equal(t, "0 1\n10 -1\n", dump)
  171. assert.Equal(t, int64(10), status[1])
  172. }
  173. func TestDeleteFile(t *testing.T) {
  174. file, status, alloc := fixtureFile()
  175. file.Update(1, 10, 0, 10)
  176. dump := file.Dump()
  177. // Output:
  178. // 0 0
  179. // 90 -1
  180. assert.Equal(t, "0 0\n90 -1\n", dump)
  181. assert.Equal(t, int64(90), status[0])
  182. assert.Equal(t, int64(0), status[1])
  183. assert.Equal(t, alloc.Size(), 3)
  184. }
  185. func TestFusedFile(t *testing.T) {
  186. file, status, alloc := fixtureFile()
  187. file.Update(1, 10, 6, 7)
  188. dump := file.Dump()
  189. // Output:
  190. // 0 0
  191. // 10 1
  192. // 16 0
  193. // 99 -1
  194. assert.Equal(t, "0 0\n10 1\n16 0\n99 -1\n", dump)
  195. assert.Equal(t, int64(93), status[0])
  196. assert.Equal(t, int64(6), status[1])
  197. file.Update(3, 10, 0, 6)
  198. dump = file.Dump()
  199. assert.Equal(t, "0 0\n93 -1\n", dump)
  200. assert.Equal(t, alloc.Size(), 5)
  201. file.Update(3, 10, 6, 0) // +2 nodes
  202. assert.Equal(t, alloc.Size(), 5) // using gaps
  203. file.Update(4, 10, 6, 0)
  204. assert.Equal(t, alloc.Size(), 6)
  205. }
  206. func TestDeleteSameBeginning(t *testing.T) {
  207. file, _, _ := fixtureFile()
  208. file.Update(1, 0, 5, 0)
  209. dump := file.Dump()
  210. // Output:
  211. // 0 0
  212. // 10 1
  213. // 16 0
  214. // 99 -1
  215. assert.Equal(t, "0 1\n5 0\n105 -1\n", dump)
  216. file.Update(3, 0, 0, 5)
  217. dump = file.Dump()
  218. assert.Equal(t, "0 0\n100 -1\n", dump)
  219. }
  220. func TestInsertSameTimeFile(t *testing.T) {
  221. file, status, _ := fixtureFile()
  222. file.Update(0, 5, 10, 0)
  223. dump := file.Dump()
  224. // Output:
  225. // 0 0
  226. // 110 -1
  227. assert.Equal(t, "0 0\n110 -1\n", dump)
  228. assert.Equal(t, int64(110), status[0])
  229. }
  230. func TestInsertSameStartFile(t *testing.T) {
  231. file, status, _ := fixtureFile()
  232. file.Update(1, 10, 10, 0)
  233. file.Update(2, 10, 10, 0)
  234. dump := file.Dump()
  235. // Output:
  236. // 0 0
  237. // 10 2
  238. // 20 1
  239. // 30 0
  240. // 120 -1
  241. assert.Equal(t, "0 0\n10 2\n20 1\n30 0\n120 -1\n", dump)
  242. assert.Equal(t, int64(100), status[0])
  243. assert.Equal(t, int64(10), status[1])
  244. assert.Equal(t, int64(10), status[2])
  245. }
  246. func TestInsertEndFile(t *testing.T) {
  247. file, status, _ := fixtureFile()
  248. file.Update(1, 100, 10, 0)
  249. dump := file.Dump()
  250. // Output:
  251. // 0 0
  252. // 100 1
  253. // 110 -1
  254. assert.Equal(t, "0 0\n100 1\n110 -1\n", dump)
  255. assert.Equal(t, int64(100), status[0])
  256. assert.Equal(t, int64(10), status[1])
  257. }
  258. func TestDeleteSameStart0File(t *testing.T) {
  259. file, status, _ := fixtureFile()
  260. file.Update(1, 0, 0, 10)
  261. dump := file.Dump()
  262. // Output:
  263. // 0 0
  264. // 90 -1
  265. assert.Equal(t, "0 0\n90 -1\n", dump)
  266. assert.Equal(t, int64(90), status[0])
  267. assert.Equal(t, int64(0), status[1])
  268. }
  269. func TestDeleteSameStartMiddleFile(t *testing.T) {
  270. file, status, _ := fixtureFile()
  271. file.Update(1, 10, 10, 0)
  272. file.Update(2, 10, 0, 5)
  273. dump := file.Dump()
  274. // Output:
  275. // 0 0
  276. // 10 1
  277. // 15 0
  278. // 105 -1
  279. assert.Equal(t, "0 0\n10 1\n15 0\n105 -1\n", dump)
  280. assert.Equal(t, int64(100), status[0])
  281. assert.Equal(t, int64(5), status[1])
  282. }
  283. func TestDeleteIntersectionFile(t *testing.T) {
  284. file, status, _ := fixtureFile()
  285. file.Update(1, 10, 10, 0)
  286. file.Update(2, 15, 0, 10)
  287. dump := file.Dump()
  288. // Output:
  289. // 0 0
  290. // 10 1
  291. // 15 0
  292. // 100 -1
  293. assert.Equal(t, "0 0\n10 1\n15 0\n100 -1\n", dump)
  294. assert.Equal(t, int64(95), status[0])
  295. assert.Equal(t, int64(5), status[1])
  296. }
  297. func TestDeleteAllFile(t *testing.T) {
  298. file, status, _ := fixtureFile()
  299. file.Update(1, 0, 0, 100)
  300. // Output:
  301. // 0 -1
  302. dump := file.Dump()
  303. assert.Equal(t, "0 -1\n", dump)
  304. assert.Equal(t, int64(0), status[0])
  305. assert.Equal(t, int64(0), status[1])
  306. }
  307. func TestFusedIntersectionFile(t *testing.T) {
  308. file, status, _ := fixtureFile()
  309. file.Update(1, 10, 10, 0)
  310. file.Update(2, 15, 3, 10)
  311. dump := file.Dump()
  312. // Output:
  313. // 0 0
  314. // 10 1
  315. // 15 2
  316. // 18 0
  317. // 103 -1
  318. assert.Equal(t, "0 0\n10 1\n15 2\n18 0\n103 -1\n", dump)
  319. assert.Equal(t, int64(95), status[0])
  320. assert.Equal(t, int64(5), status[1])
  321. assert.Equal(t, int64(3), status[2])
  322. }
  323. func TestTortureFile(t *testing.T) {
  324. file, status, _ := fixtureFile()
  325. // 0 0 | 100 -1 [0]: 100
  326. file.Update(1, 20, 30, 0)
  327. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  328. file.Update(2, 20, 0, 5)
  329. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  330. file.Update(3, 20, 0, 5)
  331. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  332. file.Update(4, 20, 10, 0)
  333. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  334. file.Update(5, 45, 0, 10)
  335. // 0 0 | 20 4 | 30 1 | 45 0 | 120 -1 [0]: 95, [1]: 15, [4]: 10
  336. file.Update(6, 45, 5, 0)
  337. // 0 0 | 20 4 | 30 1 | 45 6 | 50 0 | 125 -1 [0]: 95, [1]: 15, [4]: 10, [6]: 5
  338. file.Update(7, 10, 0, 50)
  339. // 0 0 | 75 -1 [0]: 75
  340. file.Update(8, 0, 10, 10)
  341. // 0 8 | 10 0 | 75 -1 [0]: 65, [8]: 10
  342. dump := file.Dump()
  343. assert.Equal(t, "0 8\n10 0\n75 -1\n", dump)
  344. assert.Equal(t, int64(65), status[0])
  345. assert.Equal(t, int64(0), status[1])
  346. assert.Equal(t, int64(0), status[2])
  347. assert.Equal(t, int64(0), status[3])
  348. assert.Equal(t, int64(0), status[4])
  349. assert.Equal(t, int64(0), status[5])
  350. assert.Equal(t, int64(0), status[6])
  351. assert.Equal(t, int64(0), status[7])
  352. assert.Equal(t, int64(10), status[8])
  353. }
  354. func TestInsertDeleteSameTimeFile(t *testing.T) {
  355. file, status, _ := fixtureFile()
  356. file.Update(0, 10, 10, 20)
  357. dump := file.Dump()
  358. assert.Equal(t, "0 0\n90 -1\n", dump)
  359. assert.Equal(t, int64(90), status[0])
  360. file.Update(0, 10, 20, 10)
  361. dump = file.Dump()
  362. assert.Equal(t, "0 0\n100 -1\n", dump)
  363. assert.Equal(t, int64(100), status[0])
  364. }
  365. func TestBug1File(t *testing.T) {
  366. file, status, _ := fixtureFile()
  367. file.Update(316, 1, 86, 0)
  368. file.Update(316, 87, 0, 99)
  369. file.Update(251, 0, 1, 0)
  370. file.Update(251, 1, 0, 1)
  371. dump := file.Dump()
  372. assert.Equal(t, "0 251\n1 316\n87 -1\n", dump)
  373. assert.Equal(t, int64(1), status[251])
  374. assert.Equal(t, int64(86), status[316])
  375. file.Update(316, 0, 0, 1)
  376. file.Update(316, 0, 1, 0)
  377. dump = file.Dump()
  378. assert.Equal(t, "0 316\n87 -1\n", dump)
  379. assert.Equal(t, int64(0), status[251])
  380. assert.Equal(t, int64(87), status[316])
  381. }
  382. func TestBug2File(t *testing.T) {
  383. file, status, _ := fixtureFile()
  384. file.Update(316, 1, 86, 0)
  385. file.Update(316, 87, 0, 99)
  386. file.Update(251, 0, 1, 0)
  387. file.Update(251, 1, 0, 1)
  388. dump := file.Dump()
  389. assert.Equal(t, "0 251\n1 316\n87 -1\n", dump)
  390. file.Update(316, 0, 1, 1)
  391. dump = file.Dump()
  392. assert.Equal(t, "0 316\n87 -1\n", dump)
  393. assert.Equal(t, int64(0), status[251])
  394. assert.Equal(t, int64(87), status[316])
  395. }
  396. func TestJoinFile(t *testing.T) {
  397. file, status, _ := fixtureFile()
  398. file.Update(1, 10, 10, 0)
  399. file.Update(1, 30, 10, 0)
  400. file.Update(1, 20, 10, 10)
  401. dump := file.Dump()
  402. assert.Equal(t, "0 0\n10 1\n40 0\n120 -1\n", dump)
  403. assert.Equal(t, int64(90), status[0])
  404. assert.Equal(t, int64(30), status[1])
  405. }
  406. func TestBug3File(t *testing.T) {
  407. file, status, _ := fixtureFile()
  408. file.Update(0, 1, 0, 99)
  409. file.Update(0, 0, 1, 1)
  410. dump := file.Dump()
  411. assert.Equal(t, "0 0\n1 -1\n", dump)
  412. assert.Equal(t, int64(1), status[0])
  413. }
  414. func TestBug4File(t *testing.T) {
  415. status := map[int]int64{}
  416. alloc := rbtree.NewAllocator()
  417. file := NewFile(0, 10, alloc, func(a, b, c int) {
  418. updateStatusFile(status, a, b, c)
  419. })
  420. // 0 0 | 10 -1
  421. file.Update(125, 0, 20, 9)
  422. // 0 125 | 20 0 | 21 -1
  423. file.Update(125, 0, 20, 20)
  424. // 0 125 | 20 0 | 21 -1
  425. file.Update(166, 12, 1, 1)
  426. // 0 125 | 12 166 | 13 125 | 20 0 | 21 -1
  427. file.Update(214, 2, 1, 1)
  428. // 0 125 | 2 214 | 3 125 | 12 166 | 13 125 | 20 0 | 21 -1
  429. file.Update(214, 4, 9, 0)
  430. // 0 125 | 2 214 | 3 125 | 4 214 | 13 125 | 21 166 | 22 125 | 29 0 | 30 -1
  431. file.Update(214, 27, 1, 1)
  432. // 0 125 | 2 214 | 3 125 | 4 214 | 13 125 | 21 166 | 22 125 | 27 214 | 28 125 | 29 0 | 30 -1
  433. file.Update(215, 3, 1, 1)
  434. // 0 125 | 2 214 | 3 215 | 4 214 | 13 125 | 21 166 | 22 125 | 27 214 | 28 125 | 29 0 | 30 -1
  435. file.Update(215, 13, 1, 1)
  436. // 0 125 | 2 214 | 3 215 | 4 214 | 13 215 | 14 125 | 21 166 | 22 125 | 27 214 | 28 125 | 29 0 | 30 -1
  437. file.Update(215, 17, 1, 1)
  438. // 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
  439. file.Update(215, 19, 5, 0)
  440. // 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
  441. file.Update(215, 25, 0, 1)
  442. // 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
  443. file.Update(215, 31, 6, 1)
  444. // 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
  445. file.Update(215, 27, 15, 0)
  446. // 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
  447. file.Update(215, 2, 25, 4)
  448. // 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
  449. file.Update(215, 28, 1, 1)
  450. // 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
  451. file.Update(215, 30, 7, 2)
  452. // 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
  453. file.Update(215, 38, 1, 0)
  454. // 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
  455. file.Update(215, 40, 4, 2)
  456. // 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
  457. file.Update(215, 46, 1, 0)
  458. // 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
  459. file.Update(215, 49, 1, 0)
  460. // 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
  461. file.Update(215, 52, 2, 6)
  462. // 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
  463. dump := file.Dump()
  464. 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)
  465. file.Update(214, 38, 1, 1)
  466. // 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
  467. dump = file.Dump()
  468. 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)
  469. file.Update(300, 28, 1, 1)
  470. // 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
  471. dump = file.Dump()
  472. 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)
  473. assert.Equal(t, 1+file.tree.Len(), alloc.Used())
  474. assert.Equal(t, file.Nodes(), file.tree.Len())
  475. }
  476. func TestBug5File(t *testing.T) {
  477. status := map[int]int64{}
  478. keys := []int{0, 2, 4, 7, 10}
  479. vals := []int{24, 28, 24, 28, math.MaxUint32}
  480. file := NewFileFromTree(keys, vals, rbtree.NewAllocator(), func(a, b, c int) {
  481. updateStatusFile(status, a, b, c)
  482. })
  483. file.Update(28, 0, 1, 3)
  484. dump := file.Dump()
  485. assert.Equal(t, "0 28\n2 24\n5 28\n8 -1\n", dump)
  486. keys = []int{0, 1, 16, 18}
  487. vals = []int{305, 0, 157, math.MaxUint32}
  488. file = NewFileFromTree(keys, vals, rbtree.NewAllocator(), func(a, b, c int) {
  489. updateStatusFile(status, a, b, c)
  490. })
  491. file.Update(310, 0, 0, 2)
  492. dump = file.Dump()
  493. assert.Equal(t, "0 0\n14 157\n16 -1\n", dump)
  494. }
  495. func TestNewFileFromTreeInvalidSize(t *testing.T) {
  496. keys := [...]int{1, 2, 3}
  497. vals := [...]int{4, 5}
  498. assert.Panics(t, func() { NewFileFromTree(keys[:], vals[:], rbtree.NewAllocator()) })
  499. }
  500. func TestUpdatePanic(t *testing.T) {
  501. keys := [...]int{0}
  502. vals := [...]int{math.MaxUint32}
  503. file := NewFileFromTree(keys[:], vals[:], rbtree.NewAllocator())
  504. file.tree.DeleteWithKey(0)
  505. file.tree.Insert(rbtree.Item{Key: 1, Value: math.MaxUint32})
  506. assert.PanicsWithValue(t, "invalid tree state", func() { file.Update(1, 0, 1, 0) })
  507. file.tree.Insert(rbtree.Item{Key: 0, Value: math.MaxUint32})
  508. assert.PanicsWithValue(
  509. t, "time may not be >= MaxUint32", func() { file.Update(math.MaxUint32, 0, 1, 0) })
  510. }
  511. func TestFileValidate(t *testing.T) {
  512. keys := [...]int{0}
  513. vals := [...]int{math.MaxUint32}
  514. file := NewFileFromTree(keys[:], vals[:], rbtree.NewAllocator())
  515. file.tree.DeleteWithKey(0)
  516. file.tree.Insert(rbtree.Item{Key: 1, Value: math.MaxUint32})
  517. assert.Panics(t, func() { file.Validate() })
  518. file.tree.DeleteWithKey(1)
  519. file.tree.Insert(rbtree.Item{Key: 0, Value: math.MaxUint32})
  520. file.Validate()
  521. file.tree.DeleteWithKey(0)
  522. file.tree.Insert(rbtree.Item{Key: 0, Value: 0})
  523. assert.Panics(t, func() { file.Validate() })
  524. file.tree.DeleteWithKey(0)
  525. file.tree.Insert(rbtree.Item{Key: 0, Value: 1})
  526. file.tree.Insert(rbtree.Item{Key: 1, Value: 1})
  527. file.tree.Insert(rbtree.Item{Key: 2, Value: math.MaxUint32})
  528. file.Validate()
  529. file.tree.FindGE(2).Item().Key = 1
  530. assert.Panics(t, func() { file.Validate() })
  531. }
  532. func TestFileFlatten(t *testing.T) {
  533. file, _, _ := fixtureFile()
  534. // 0 0 | 100 -1 [0]: 100
  535. file.Update(1, 20, 30, 0)
  536. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  537. file.Update(2, 20, 0, 5)
  538. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  539. file.Update(3, 20, 0, 5)
  540. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  541. file.Update(4, 20, 10, 0)
  542. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  543. lines := file.flatten()
  544. for i := 0; i < 20; i++ {
  545. assert.Equal(t, 0, lines[i], fmt.Sprintf("line %d", i))
  546. }
  547. for i := 20; i < 30; i++ {
  548. assert.Equal(t, 4, lines[i], fmt.Sprintf("line %d", i))
  549. }
  550. for i := 30; i < 50; i++ {
  551. assert.Equal(t, 1, lines[i], fmt.Sprintf("line %d", i))
  552. }
  553. for i := 50; i < 130; i++ {
  554. assert.Equal(t, 0, lines[i], fmt.Sprintf("line %d", i))
  555. }
  556. assert.Len(t, lines, 130)
  557. }
  558. func TestFileMergeMark(t *testing.T) {
  559. file, status, _ := fixtureFile()
  560. // 0 0 | 100 -1 [0]: 100
  561. file.Update(1, 20, 30, 0)
  562. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  563. file.Update(2, 20, 0, 5)
  564. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  565. file.Update(3, 20, 0, 5)
  566. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  567. file.Update(4, 20, 10, 0)
  568. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  569. file.Update(TreeMergeMark, 60, 20, 20)
  570. // 0 0 | 20 4 | 30 1 | 50 0 | 60 M | 80 0 | 130 -1
  571. // [0]: 100, [1]: 20, [4]: 10
  572. dump := file.Dump()
  573. assert.Equal(t, "0 0\n20 4\n30 1\n50 0\n60 16383\n80 0\n130 -1\n", dump)
  574. assert.Contains(t, status, 0)
  575. assert.Equal(t, int64(100), status[0])
  576. assert.Equal(t, int64(20), status[1])
  577. assert.Equal(t, int64(0), status[2])
  578. assert.Equal(t, int64(0), status[3])
  579. assert.Equal(t, int64(10), status[4])
  580. assert.NotContains(t, status, TreeMergeMark)
  581. }
  582. func TestFileMergeShallow(t *testing.T) {
  583. file1, status, alloc := fixtureFile()
  584. // 0 0 | 100 -1 [0]: 100
  585. file1.Update(1, 20, 30, 0)
  586. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  587. file1.Update(2, 20, 0, 5)
  588. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  589. file1.Update(3, 20, 0, 5)
  590. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  591. file1.Update(4, 20, 10, 0)
  592. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  593. file2 := file1.CloneShallow(alloc.Clone())
  594. file1.Update(TreeMergeMark, 60, 30, 30)
  595. // 0 0 | 20 4 | 30 1 | 50 0 | 60 M | 90 0 | 130 -1
  596. // [0]: 70, [1]: 20, [4]: 10
  597. file2.Update(5, 60, 20, 20)
  598. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 0 | 130 -1
  599. // [0]: 80, [1]: 20, [4]: 10, [5]: 20
  600. file2.Update(TreeMergeMark, 80, 10, 10)
  601. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 M | 90 0 | 130 -1
  602. // [0]: 70, [1]: 20, [4]: 10, [5]: 20
  603. file2.Update(6, 0, 10, 10)
  604. // 0 6 | 10 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 M | 90 0 | 130 -1
  605. // [0]: 60, [1]: 20, [4]: 10, [5]: 20, [6]: 10
  606. file1.Merge(7, file2)
  607. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 7 | 90 0 | 130 -1
  608. // [0]: 70, [1]: 20, [4]: 10, [5]: 20, [6]: 0, [7]: 10
  609. dump := file1.Dump()
  610. assert.Equal(t, "0 0\n20 4\n30 1\n50 0\n60 5\n80 7\n90 0\n130 -1\n", dump)
  611. assert.Equal(t, int64(70), status[0])
  612. assert.Equal(t, int64(20), status[1])
  613. assert.Equal(t, int64(0), status[2])
  614. assert.Equal(t, int64(0), status[3])
  615. assert.Equal(t, int64(10), status[4])
  616. assert.Equal(t, int64(20), status[5])
  617. assert.Equal(t, int64(10), status[6])
  618. assert.Equal(t, int64(10), status[7])
  619. }
  620. func TestFileMergeDeep(t *testing.T) {
  621. file1, status, _ := fixtureFile()
  622. // 0 0 | 100 -1 [0]: 100
  623. file1.Update(1, 20, 30, 0)
  624. // 0 0 | 20 1 | 50 0 | 130 -1 [0]: 100, [1]: 30
  625. file1.Update(2, 20, 0, 5)
  626. // 0 0 | 20 1 | 45 0 | 125 -1 [0]: 100, [1]: 25
  627. file1.Update(3, 20, 0, 5)
  628. // 0 0 | 20 1 | 40 0 | 120 -1 [0]: 100, [1]: 20
  629. file1.Update(4, 20, 10, 0)
  630. // 0 0 | 20 4 | 30 1 | 50 0 | 130 -1 [0]: 100, [1]: 20, [4]: 10
  631. file2 := file1.CloneDeep(rbtree.NewAllocator())
  632. file1.Update(TreeMergeMark, 60, 30, 30)
  633. // 0 0 | 20 4 | 30 1 | 50 0 | 60 M | 90 0 | 130 -1
  634. // [0]: 70, [1]: 20, [4]: 10
  635. file2.Update(5, 60, 20, 20)
  636. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 0 | 130 -1
  637. // [0]: 80, [1]: 20, [4]: 10, [5]: 20
  638. file2.Update(TreeMergeMark, 80, 10, 10)
  639. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 M | 90 0 | 130 -1
  640. // [0]: 70, [1]: 20, [4]: 10, [5]: 20
  641. file2.Update(6, 0, 10, 10)
  642. // 0 6 | 10 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 M | 90 0 | 130 -1
  643. // [0]: 60, [1]: 20, [4]: 10, [5]: 20, [6]: 10
  644. file1.Merge(7, file2)
  645. // 0 0 | 20 4 | 30 1 | 50 0 | 60 5 | 80 7 | 90 0 | 130 -1
  646. // [0]: 70, [1]: 20, [4]: 10, [5]: 20, [6]: 0, [7]: 10
  647. dump := file1.Dump()
  648. assert.Equal(t, "0 0\n20 4\n30 1\n50 0\n60 5\n80 7\n90 0\n130 -1\n", dump)
  649. assert.Equal(t, int64(70), status[0])
  650. assert.Equal(t, int64(20), status[1])
  651. assert.Equal(t, int64(0), status[2])
  652. assert.Equal(t, int64(0), status[3])
  653. assert.Equal(t, int64(10), status[4])
  654. assert.Equal(t, int64(20), status[5])
  655. assert.Equal(t, int64(10), status[6])
  656. assert.Equal(t, int64(10), status[7])
  657. }
  658. func TestFileMergeNoop(t *testing.T) {
  659. file1, _, _ := fixtureFile()
  660. // 0 0 | 100 -1 [0]: 100
  661. assert.Panics(t, func() { file1.Merge(3, nil) })
  662. }
  663. func TestFileMergeNil(t *testing.T) {
  664. file, _, _ := fixtureFile()
  665. assert.Panics(t, func() {
  666. file.Merge(1, nil)
  667. })
  668. }
  669. func TestBug6File(t *testing.T) {
  670. status := map[int]int64{}
  671. keys := []int{0, 113, 153, 154}
  672. vals := []int{7, 10, 7, math.MaxUint32}
  673. file := NewFileFromTree(keys, vals, rbtree.NewAllocator(), func(a, b, c int) {
  674. updateStatusFile(status, a, b, c)
  675. })
  676. // 0 7 | 113 10 | 153 7 | 154 -1
  677. file.Update(10, 99, 1, 1)
  678. // 0 7 | 99 10 | 100 7 | 113 10 | 153 7 | 154 -1
  679. file.Update(10, 104, 1, 1)
  680. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 113 10 | 153 7 | 154 -1
  681. file.Update(10, 106, 1, 1)
  682. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 106 10 | 107 7 | 113 10 | 153 7 | 154 -1
  683. file.Update(10, 108, 1, 1)
  684. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 106 10 | 107 7 | 108 10 | 109 7 | 113 10 | 153 7 | 154 -1
  685. file.Update(10, 115, 2, 0)
  686. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 106 10 | 107 7 | 108 10 | 109 7 | 113 10 | 155 7 | 156 -1
  687. file.Update(10, 125, 4, 2)
  688. // 0 7 | 99 10 | 100 7 | 104 10 | 105 7 | 106 10 | 107 7 | 108 10 | 109 7 | 113 10 | 157 7 | 158 -1
  689. dump := file.Dump()
  690. 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)
  691. file = NewFileFromTree(keys, vals, rbtree.NewAllocator(), func(a, b, c int) {
  692. updateStatusFile(status, a, b, c)
  693. })
  694. // 0 7 | 113 10 | 153 7 | 154 -1
  695. file.Update(10, 112, 1, 1)
  696. // 0 7 | 112 10 | 153 7 | 154 -1
  697. dump = file.Dump()
  698. assert.Equal(t, "0 7\n112 10\n153 7\n154 -1\n", dump)
  699. }