file_test.go 19 KB

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