file_test.go 19 KB

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