file_test.go 23 KB

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