burndown_test.go 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. package hercules
  2. import (
  3. "bytes"
  4. "io"
  5. "io/ioutil"
  6. "path"
  7. "testing"
  8. "github.com/gogo/protobuf/proto"
  9. "github.com/stretchr/testify/assert"
  10. "gopkg.in/src-d/go-git.v4/plumbing"
  11. "gopkg.in/src-d/go-git.v4/plumbing/object"
  12. "gopkg.in/src-d/hercules.v3/pb"
  13. )
  14. func TestBurndownMeta(t *testing.T) {
  15. burndown := BurndownAnalysis{}
  16. assert.Equal(t, burndown.Name(), "Burndown")
  17. assert.Equal(t, len(burndown.Provides()), 0)
  18. required := [...]string{DependencyFileDiff, DependencyTreeChanges, DependencyBlobCache, DependencyDay, DependencyAuthor}
  19. for _, name := range required {
  20. assert.Contains(t, burndown.Requires(), name)
  21. }
  22. opts := burndown.ListConfigurationOptions()
  23. matches := 0
  24. for _, opt := range opts {
  25. switch opt.Name {
  26. case ConfigBurndownGranularity, ConfigBurndownSampling, ConfigBurndownTrackFiles,
  27. ConfigBurndownTrackPeople, ConfigBurndownDebug:
  28. matches++
  29. }
  30. }
  31. assert.Len(t, opts, matches)
  32. assert.Equal(t, burndown.Flag(), "burndown")
  33. }
  34. func TestBurndownConfigure(t *testing.T) {
  35. burndown := BurndownAnalysis{}
  36. facts := map[string]interface{}{}
  37. facts[ConfigBurndownGranularity] = 100
  38. facts[ConfigBurndownSampling] = 200
  39. facts[ConfigBurndownTrackFiles] = true
  40. facts[ConfigBurndownTrackPeople] = true
  41. facts[ConfigBurndownDebug] = true
  42. facts[FactIdentityDetectorPeopleCount] = 5
  43. facts[FactIdentityDetectorReversedPeopleDict] = burndown.Requires()
  44. burndown.Configure(facts)
  45. assert.Equal(t, burndown.Granularity, 100)
  46. assert.Equal(t, burndown.Sampling, 200)
  47. assert.Equal(t, burndown.TrackFiles, true)
  48. assert.Equal(t, burndown.PeopleNumber, 5)
  49. assert.Equal(t, burndown.Debug, true)
  50. assert.Equal(t, burndown.reversedPeopleDict, burndown.Requires())
  51. facts[ConfigBurndownTrackPeople] = false
  52. facts[FactIdentityDetectorPeopleCount] = 50
  53. burndown.Configure(facts)
  54. assert.Equal(t, burndown.PeopleNumber, 0)
  55. facts = map[string]interface{}{}
  56. burndown.Configure(facts)
  57. assert.Equal(t, burndown.Granularity, 100)
  58. assert.Equal(t, burndown.Sampling, 200)
  59. assert.Equal(t, burndown.TrackFiles, true)
  60. assert.Equal(t, burndown.PeopleNumber, 0)
  61. assert.Equal(t, burndown.Debug, true)
  62. assert.Equal(t, burndown.reversedPeopleDict, burndown.Requires())
  63. }
  64. func TestBurndownRegistration(t *testing.T) {
  65. tp, exists := Registry.registered[(&BurndownAnalysis{}).Name()]
  66. assert.True(t, exists)
  67. assert.Equal(t, tp.Elem().Name(), "BurndownAnalysis")
  68. tp, exists = Registry.flags[(&BurndownAnalysis{}).Flag()]
  69. assert.True(t, exists)
  70. assert.Equal(t, tp.Elem().Name(), "BurndownAnalysis")
  71. }
  72. func TestBurndownInitialize(t *testing.T) {
  73. burndown := BurndownAnalysis{}
  74. burndown.Sampling = -10
  75. burndown.Granularity = DefaultBurndownGranularity
  76. burndown.Initialize(testRepository)
  77. assert.Equal(t, burndown.Sampling, DefaultBurndownGranularity)
  78. assert.Equal(t, burndown.Granularity, DefaultBurndownGranularity)
  79. burndown.Sampling = 0
  80. burndown.Granularity = DefaultBurndownGranularity - 1
  81. burndown.Initialize(testRepository)
  82. assert.Equal(t, burndown.Sampling, DefaultBurndownGranularity-1)
  83. assert.Equal(t, burndown.Granularity, DefaultBurndownGranularity-1)
  84. burndown.Sampling = DefaultBurndownGranularity - 1
  85. burndown.Granularity = -10
  86. burndown.Initialize(testRepository)
  87. assert.Equal(t, burndown.Sampling, DefaultBurndownGranularity-1)
  88. assert.Equal(t, burndown.Granularity, DefaultBurndownGranularity)
  89. }
  90. func TestBurndownConsumeFinalize(t *testing.T) {
  91. burndown := BurndownAnalysis{
  92. Granularity: 30,
  93. Sampling: 30,
  94. PeopleNumber: 2,
  95. TrackFiles: true,
  96. }
  97. burndown.Initialize(testRepository)
  98. deps := map[string]interface{}{}
  99. // stage 1
  100. deps[DependencyAuthor] = 0
  101. deps[DependencyDay] = 0
  102. cache := map[plumbing.Hash]*object.Blob{}
  103. hash := plumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe")
  104. cache[hash], _ = testRepository.BlobObject(hash)
  105. hash = plumbing.NewHash("c29112dbd697ad9b401333b80c18a63951bc18d9")
  106. cache[hash], _ = testRepository.BlobObject(hash)
  107. hash = plumbing.NewHash("baa64828831d174f40140e4b3cfa77d1e917a2c1")
  108. cache[hash], _ = testRepository.BlobObject(hash)
  109. hash = plumbing.NewHash("dc248ba2b22048cc730c571a748e8ffcf7085ab9")
  110. cache[hash], _ = testRepository.BlobObject(hash)
  111. deps[DependencyBlobCache] = cache
  112. changes := make(object.Changes, 3)
  113. treeFrom, _ := testRepository.TreeObject(plumbing.NewHash(
  114. "a1eb2ea76eb7f9bfbde9b243861474421000eb96"))
  115. treeTo, _ := testRepository.TreeObject(plumbing.NewHash(
  116. "994eac1cd07235bb9815e547a75c84265dea00f5"))
  117. changes[0] = &object.Change{From: object.ChangeEntry{
  118. Name: "analyser.go",
  119. Tree: treeFrom,
  120. TreeEntry: object.TreeEntry{
  121. Name: "analyser.go",
  122. Mode: 0100644,
  123. Hash: plumbing.NewHash("dc248ba2b22048cc730c571a748e8ffcf7085ab9"),
  124. },
  125. }, To: object.ChangeEntry{
  126. Name: "analyser.go",
  127. Tree: treeTo,
  128. TreeEntry: object.TreeEntry{
  129. Name: "analyser.go",
  130. Mode: 0100644,
  131. Hash: plumbing.NewHash("baa64828831d174f40140e4b3cfa77d1e917a2c1"),
  132. },
  133. }}
  134. changes[1] = &object.Change{From: object.ChangeEntry{}, To: object.ChangeEntry{
  135. Name: "cmd/hercules/main.go",
  136. Tree: treeTo,
  137. TreeEntry: object.TreeEntry{
  138. Name: "cmd/hercules/main.go",
  139. Mode: 0100644,
  140. Hash: plumbing.NewHash("c29112dbd697ad9b401333b80c18a63951bc18d9"),
  141. },
  142. },
  143. }
  144. changes[2] = &object.Change{From: object.ChangeEntry{}, To: object.ChangeEntry{
  145. Name: ".travis.yml",
  146. Tree: treeTo,
  147. TreeEntry: object.TreeEntry{
  148. Name: ".travis.yml",
  149. Mode: 0100644,
  150. Hash: plumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe"),
  151. },
  152. },
  153. }
  154. deps[DependencyTreeChanges] = changes
  155. fd := fixtureFileDiff()
  156. result, err := fd.Consume(deps)
  157. assert.Nil(t, err)
  158. deps[DependencyFileDiff] = result[DependencyFileDiff]
  159. result, err = burndown.Consume(deps)
  160. assert.Nil(t, result)
  161. assert.Nil(t, err)
  162. assert.Equal(t, burndown.previousDay, 0)
  163. assert.Equal(t, len(burndown.files), 3)
  164. assert.Equal(t, burndown.files["cmd/hercules/main.go"].Len(), 207)
  165. assert.Equal(t, burndown.files["analyser.go"].Len(), 926)
  166. assert.Equal(t, burndown.files[".travis.yml"].Len(), 12)
  167. assert.Equal(t, len(burndown.people), 2)
  168. assert.Equal(t, burndown.people[0][0], int64(12+207+926))
  169. assert.Equal(t, len(burndown.globalStatus), 1)
  170. assert.Equal(t, burndown.globalStatus[0], int64(12+207+926))
  171. assert.Equal(t, len(burndown.globalHistory), 0)
  172. assert.Equal(t, len(burndown.fileHistories), 0)
  173. burndown2 := BurndownAnalysis{
  174. Granularity: 30,
  175. Sampling: 0,
  176. }
  177. burndown2.Initialize(testRepository)
  178. _, err = burndown2.Consume(deps)
  179. assert.Nil(t, err)
  180. assert.Equal(t, len(burndown2.people), 0)
  181. assert.Equal(t, len(burndown2.peopleHistories), 0)
  182. assert.Equal(t, len(burndown2.fileHistories), 0)
  183. // stage 2
  184. // 2b1ed978194a94edeabbca6de7ff3b5771d4d665
  185. deps[DependencyAuthor] = 1
  186. deps[DependencyDay] = 30
  187. cache = map[plumbing.Hash]*object.Blob{}
  188. hash = plumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe")
  189. cache[hash], _ = testRepository.BlobObject(hash)
  190. hash = plumbing.NewHash("baa64828831d174f40140e4b3cfa77d1e917a2c1")
  191. cache[hash], _ = testRepository.BlobObject(hash)
  192. hash = plumbing.NewHash("29c9fafd6a2fae8cd20298c3f60115bc31a4c0f2")
  193. cache[hash], _ = testRepository.BlobObject(hash)
  194. hash = plumbing.NewHash("c29112dbd697ad9b401333b80c18a63951bc18d9")
  195. cache[hash], _ = testRepository.BlobObject(hash)
  196. hash = plumbing.NewHash("f7d918ec500e2f925ecde79b51cc007bac27de72")
  197. cache[hash], _ = testRepository.BlobObject(hash)
  198. deps[DependencyBlobCache] = cache
  199. changes = make(object.Changes, 3)
  200. treeFrom, _ = testRepository.TreeObject(plumbing.NewHash(
  201. "96c6ece9b2f3c7c51b83516400d278dea5605100"))
  202. treeTo, _ = testRepository.TreeObject(plumbing.NewHash(
  203. "251f2094d7b523d5bcc60e663b6cf38151bf8844"))
  204. changes[0] = &object.Change{From: object.ChangeEntry{
  205. Name: "analyser.go",
  206. Tree: treeFrom,
  207. TreeEntry: object.TreeEntry{
  208. Name: "analyser.go",
  209. Mode: 0100644,
  210. Hash: plumbing.NewHash("baa64828831d174f40140e4b3cfa77d1e917a2c1"),
  211. },
  212. }, To: object.ChangeEntry{
  213. Name: "burndown.go",
  214. Tree: treeTo,
  215. TreeEntry: object.TreeEntry{
  216. Name: "burndown.go",
  217. Mode: 0100644,
  218. Hash: plumbing.NewHash("29c9fafd6a2fae8cd20298c3f60115bc31a4c0f2"),
  219. },
  220. },
  221. }
  222. changes[1] = &object.Change{From: object.ChangeEntry{
  223. Name: "cmd/hercules/main.go",
  224. Tree: treeFrom,
  225. TreeEntry: object.TreeEntry{
  226. Name: "cmd/hercules/main.go",
  227. Mode: 0100644,
  228. Hash: plumbing.NewHash("c29112dbd697ad9b401333b80c18a63951bc18d9"),
  229. },
  230. }, To: object.ChangeEntry{
  231. Name: "cmd/hercules/main.go",
  232. Tree: treeTo,
  233. TreeEntry: object.TreeEntry{
  234. Name: "cmd/hercules/main.go",
  235. Mode: 0100644,
  236. Hash: plumbing.NewHash("f7d918ec500e2f925ecde79b51cc007bac27de72"),
  237. },
  238. },
  239. }
  240. changes[2] = &object.Change{From: object.ChangeEntry{
  241. Name: ".travis.yml",
  242. Tree: treeTo,
  243. TreeEntry: object.TreeEntry{
  244. Name: ".travis.yml",
  245. Mode: 0100644,
  246. Hash: plumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe"),
  247. },
  248. }, To: object.ChangeEntry{},
  249. }
  250. deps[DependencyTreeChanges] = changes
  251. fd = fixtureFileDiff()
  252. result, err = fd.Consume(deps)
  253. assert.Nil(t, err)
  254. deps[DependencyFileDiff] = result[DependencyFileDiff]
  255. result, err = burndown.Consume(deps)
  256. assert.Nil(t, result)
  257. assert.Nil(t, err)
  258. assert.Equal(t, burndown.previousDay, 30)
  259. assert.Equal(t, len(burndown.files), 2)
  260. assert.Equal(t, burndown.files["cmd/hercules/main.go"].Len(), 290)
  261. assert.Equal(t, burndown.files["burndown.go"].Len(), 543)
  262. assert.Equal(t, len(burndown.people), 2)
  263. assert.Equal(t, len(burndown.globalStatus), 2)
  264. assert.Equal(t, burndown.globalStatus[0], int64(464))
  265. assert.Equal(t, burndown.globalStatus[1], int64(0))
  266. assert.Equal(t, len(burndown.globalHistory), 1)
  267. assert.Equal(t, len(burndown.globalHistory[0]), 2)
  268. assert.Equal(t, len(burndown.fileHistories), 3)
  269. out := burndown.Finalize().(BurndownResult)
  270. /*
  271. GlobalHistory [][]int64
  272. FileHistories map[string][][]int64
  273. PeopleHistories [][][]int64
  274. PeopleMatrix [][]int64
  275. */
  276. assert.Equal(t, len(out.GlobalHistory), 2)
  277. for i := 0; i < 2; i++ {
  278. assert.Equal(t, len(out.GlobalHistory[i]), 2)
  279. }
  280. assert.Equal(t, len(out.GlobalHistory), 2)
  281. assert.Equal(t, out.GlobalHistory[0][0], int64(1145))
  282. assert.Equal(t, out.GlobalHistory[0][1], int64(0))
  283. assert.Equal(t, out.GlobalHistory[1][0], int64(464))
  284. assert.Equal(t, out.GlobalHistory[1][1], int64(369))
  285. assert.Equal(t, len(out.FileHistories), 2)
  286. assert.Equal(t, len(out.FileHistories["cmd/hercules/main.go"]), 2)
  287. assert.Equal(t, len(out.FileHistories["burndown.go"]), 2)
  288. assert.Equal(t, len(out.FileHistories["cmd/hercules/main.go"][0]), 2)
  289. assert.Equal(t, len(out.FileHistories["burndown.go"][0]), 2)
  290. assert.Equal(t, len(out.PeopleMatrix), 2)
  291. assert.Equal(t, len(out.PeopleMatrix[0]), 4)
  292. assert.Equal(t, len(out.PeopleMatrix[1]), 4)
  293. assert.Equal(t, out.PeopleMatrix[0][0], int64(1145))
  294. assert.Equal(t, out.PeopleMatrix[0][1], int64(0))
  295. assert.Equal(t, out.PeopleMatrix[0][2], int64(0))
  296. assert.Equal(t, out.PeopleMatrix[0][3], int64(-681))
  297. assert.Equal(t, out.PeopleMatrix[1][0], int64(369))
  298. assert.Equal(t, out.PeopleMatrix[1][1], int64(0))
  299. assert.Equal(t, out.PeopleMatrix[1][2], int64(0))
  300. assert.Equal(t, out.PeopleMatrix[1][3], int64(0))
  301. assert.Equal(t, len(out.PeopleHistories), 2)
  302. for i := 0; i < 2; i++ {
  303. assert.Equal(t, len(out.PeopleHistories[i]), 2)
  304. assert.Equal(t, len(out.PeopleHistories[i][0]), 2)
  305. assert.Equal(t, len(out.PeopleHistories[i][1]), 2)
  306. }
  307. }
  308. func TestBurndownSerialize(t *testing.T) {
  309. burndown := BurndownAnalysis{
  310. Granularity: 30,
  311. Sampling: 30,
  312. PeopleNumber: 2,
  313. TrackFiles: true,
  314. }
  315. burndown.Initialize(testRepository)
  316. deps := map[string]interface{}{}
  317. // stage 1
  318. deps[DependencyAuthor] = 0
  319. deps[DependencyDay] = 0
  320. cache := map[plumbing.Hash]*object.Blob{}
  321. hash := plumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe")
  322. cache[hash], _ = testRepository.BlobObject(hash)
  323. hash = plumbing.NewHash("c29112dbd697ad9b401333b80c18a63951bc18d9")
  324. cache[hash], _ = testRepository.BlobObject(hash)
  325. hash = plumbing.NewHash("baa64828831d174f40140e4b3cfa77d1e917a2c1")
  326. cache[hash], _ = testRepository.BlobObject(hash)
  327. hash = plumbing.NewHash("dc248ba2b22048cc730c571a748e8ffcf7085ab9")
  328. cache[hash], _ = testRepository.BlobObject(hash)
  329. deps[DependencyBlobCache] = cache
  330. changes := make(object.Changes, 3)
  331. treeFrom, _ := testRepository.TreeObject(plumbing.NewHash(
  332. "a1eb2ea76eb7f9bfbde9b243861474421000eb96"))
  333. treeTo, _ := testRepository.TreeObject(plumbing.NewHash(
  334. "994eac1cd07235bb9815e547a75c84265dea00f5"))
  335. changes[0] = &object.Change{From: object.ChangeEntry{
  336. Name: "analyser.go",
  337. Tree: treeFrom,
  338. TreeEntry: object.TreeEntry{
  339. Name: "analyser.go",
  340. Mode: 0100644,
  341. Hash: plumbing.NewHash("dc248ba2b22048cc730c571a748e8ffcf7085ab9"),
  342. },
  343. }, To: object.ChangeEntry{
  344. Name: "analyser.go",
  345. Tree: treeTo,
  346. TreeEntry: object.TreeEntry{
  347. Name: "analyser.go",
  348. Mode: 0100644,
  349. Hash: plumbing.NewHash("baa64828831d174f40140e4b3cfa77d1e917a2c1"),
  350. },
  351. }}
  352. changes[1] = &object.Change{From: object.ChangeEntry{}, To: object.ChangeEntry{
  353. Name: "cmd/hercules/main.go",
  354. Tree: treeTo,
  355. TreeEntry: object.TreeEntry{
  356. Name: "cmd/hercules/main.go",
  357. Mode: 0100644,
  358. Hash: plumbing.NewHash("c29112dbd697ad9b401333b80c18a63951bc18d9"),
  359. },
  360. },
  361. }
  362. changes[2] = &object.Change{From: object.ChangeEntry{}, To: object.ChangeEntry{
  363. Name: ".travis.yml",
  364. Tree: treeTo,
  365. TreeEntry: object.TreeEntry{
  366. Name: ".travis.yml",
  367. Mode: 0100644,
  368. Hash: plumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe"),
  369. },
  370. },
  371. }
  372. deps[DependencyTreeChanges] = changes
  373. fd := fixtureFileDiff()
  374. result, _ := fd.Consume(deps)
  375. deps[DependencyFileDiff] = result[DependencyFileDiff]
  376. burndown.Consume(deps)
  377. // stage 2
  378. // 2b1ed978194a94edeabbca6de7ff3b5771d4d665
  379. deps[DependencyAuthor] = 1
  380. deps[DependencyDay] = 30
  381. cache = map[plumbing.Hash]*object.Blob{}
  382. hash = plumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe")
  383. cache[hash], _ = testRepository.BlobObject(hash)
  384. hash = plumbing.NewHash("baa64828831d174f40140e4b3cfa77d1e917a2c1")
  385. cache[hash], _ = testRepository.BlobObject(hash)
  386. hash = plumbing.NewHash("29c9fafd6a2fae8cd20298c3f60115bc31a4c0f2")
  387. cache[hash], _ = testRepository.BlobObject(hash)
  388. hash = plumbing.NewHash("c29112dbd697ad9b401333b80c18a63951bc18d9")
  389. cache[hash], _ = testRepository.BlobObject(hash)
  390. hash = plumbing.NewHash("f7d918ec500e2f925ecde79b51cc007bac27de72")
  391. cache[hash], _ = testRepository.BlobObject(hash)
  392. deps[DependencyBlobCache] = cache
  393. changes = make(object.Changes, 3)
  394. treeFrom, _ = testRepository.TreeObject(plumbing.NewHash(
  395. "96c6ece9b2f3c7c51b83516400d278dea5605100"))
  396. treeTo, _ = testRepository.TreeObject(plumbing.NewHash(
  397. "251f2094d7b523d5bcc60e663b6cf38151bf8844"))
  398. changes[0] = &object.Change{From: object.ChangeEntry{
  399. Name: "analyser.go",
  400. Tree: treeFrom,
  401. TreeEntry: object.TreeEntry{
  402. Name: "analyser.go",
  403. Mode: 0100644,
  404. Hash: plumbing.NewHash("baa64828831d174f40140e4b3cfa77d1e917a2c1"),
  405. },
  406. }, To: object.ChangeEntry{
  407. Name: "burndown.go",
  408. Tree: treeTo,
  409. TreeEntry: object.TreeEntry{
  410. Name: "burndown.go",
  411. Mode: 0100644,
  412. Hash: plumbing.NewHash("29c9fafd6a2fae8cd20298c3f60115bc31a4c0f2"),
  413. },
  414. },
  415. }
  416. changes[1] = &object.Change{From: object.ChangeEntry{
  417. Name: "cmd/hercules/main.go",
  418. Tree: treeFrom,
  419. TreeEntry: object.TreeEntry{
  420. Name: "cmd/hercules/main.go",
  421. Mode: 0100644,
  422. Hash: plumbing.NewHash("c29112dbd697ad9b401333b80c18a63951bc18d9"),
  423. },
  424. }, To: object.ChangeEntry{
  425. Name: "cmd/hercules/main.go",
  426. Tree: treeTo,
  427. TreeEntry: object.TreeEntry{
  428. Name: "cmd/hercules/main.go",
  429. Mode: 0100644,
  430. Hash: plumbing.NewHash("f7d918ec500e2f925ecde79b51cc007bac27de72"),
  431. },
  432. },
  433. }
  434. changes[2] = &object.Change{From: object.ChangeEntry{
  435. Name: ".travis.yml",
  436. Tree: treeTo,
  437. TreeEntry: object.TreeEntry{
  438. Name: ".travis.yml",
  439. Mode: 0100644,
  440. Hash: plumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe"),
  441. },
  442. }, To: object.ChangeEntry{},
  443. }
  444. deps[DependencyTreeChanges] = changes
  445. fd = fixtureFileDiff()
  446. result, _ = fd.Consume(deps)
  447. deps[DependencyFileDiff] = result[DependencyFileDiff]
  448. people := [...]string{"one@srcd", "two@srcd"}
  449. burndown.reversedPeopleDict = people[:]
  450. burndown.Consume(deps)
  451. out := burndown.Finalize().(BurndownResult)
  452. buffer := &bytes.Buffer{}
  453. burndown.Serialize(out, false, buffer)
  454. assert.Equal(t, buffer.String(), ` granularity: 30
  455. sampling: 30
  456. "project": |-
  457. 1145 0
  458. 464 369
  459. files:
  460. "burndown.go": |-
  461. 0 0
  462. 293 250
  463. "cmd/hercules/main.go": |-
  464. 207 0
  465. 171 119
  466. people_sequence:
  467. - "one@srcd"
  468. - "two@srcd"
  469. people:
  470. "one@srcd": |-
  471. 1145 0
  472. 464 0
  473. "two@srcd": |-
  474. 0 0
  475. 0 369
  476. people_interaction: |-
  477. 1145 0 0 -681
  478. 369 0 0 0
  479. `)
  480. buffer = &bytes.Buffer{}
  481. burndown.Serialize(out, true, buffer)
  482. msg := pb.BurndownAnalysisResults{}
  483. proto.Unmarshal(buffer.Bytes(), &msg)
  484. assert.Equal(t, msg.Granularity, int32(30))
  485. assert.Equal(t, msg.Sampling, int32(30))
  486. assert.Equal(t, msg.Project.Name, "project")
  487. assert.Equal(t, msg.Project.NumberOfRows, int32(2))
  488. assert.Equal(t, msg.Project.NumberOfColumns, int32(2))
  489. assert.Len(t, msg.Project.Rows, 2)
  490. assert.Len(t, msg.Project.Rows[0].Columns, 1)
  491. assert.Equal(t, msg.Project.Rows[0].Columns[0], uint32(1145))
  492. assert.Len(t, msg.Project.Rows[1].Columns, 2)
  493. assert.Equal(t, msg.Project.Rows[1].Columns[0], uint32(464))
  494. assert.Equal(t, msg.Project.Rows[1].Columns[1], uint32(369))
  495. assert.Len(t, msg.Files, 2)
  496. assert.Equal(t, msg.Files[0].Name, "burndown.go")
  497. assert.Equal(t, msg.Files[1].Name, "cmd/hercules/main.go")
  498. assert.Len(t, msg.Files[0].Rows, 2)
  499. assert.Len(t, msg.Files[0].Rows[0].Columns, 0)
  500. assert.Len(t, msg.Files[0].Rows[1].Columns, 2)
  501. assert.Equal(t, msg.Files[0].Rows[1].Columns[0], uint32(293))
  502. assert.Equal(t, msg.Files[0].Rows[1].Columns[1], uint32(250))
  503. assert.Len(t, msg.People, 2)
  504. assert.Equal(t, msg.People[0].Name, "one@srcd")
  505. assert.Equal(t, msg.People[1].Name, "two@srcd")
  506. assert.Len(t, msg.People[0].Rows, 2)
  507. assert.Len(t, msg.People[0].Rows[0].Columns, 1)
  508. assert.Len(t, msg.People[0].Rows[1].Columns, 1)
  509. assert.Equal(t, msg.People[0].Rows[0].Columns[0], uint32(1145))
  510. assert.Equal(t, msg.People[0].Rows[1].Columns[0], uint32(464))
  511. assert.Len(t, msg.People[1].Rows, 2)
  512. assert.Len(t, msg.People[1].Rows[0].Columns, 0)
  513. assert.Len(t, msg.People[1].Rows[1].Columns, 2)
  514. assert.Equal(t, msg.People[1].Rows[1].Columns[0], uint32(0))
  515. assert.Equal(t, msg.People[1].Rows[1].Columns[1], uint32(369))
  516. assert.Equal(t, msg.PeopleInteraction.NumberOfRows, int32(2))
  517. assert.Equal(t, msg.PeopleInteraction.NumberOfColumns, int32(4))
  518. data := [...]int64{1145, -681, 369}
  519. assert.Equal(t, msg.PeopleInteraction.Data, data[:])
  520. indices := [...]int32{0, 3, 0}
  521. assert.Equal(t, msg.PeopleInteraction.Indices, indices[:])
  522. indptr := [...]int64{0, 2, 3}
  523. assert.Equal(t, msg.PeopleInteraction.Indptr, indptr[:])
  524. }
  525. type panickingCloser struct {
  526. }
  527. func (c panickingCloser) Close() error {
  528. return io.EOF
  529. }
  530. func TestCheckClose(t *testing.T) {
  531. closer := panickingCloser{}
  532. assert.Panics(t, func() { checkClose(closer) })
  533. }
  534. func TestBurndownAddMatrix(t *testing.T) {
  535. size := 5*3 + 1
  536. daily := make([][]float32, size)
  537. for i := range daily {
  538. daily[i] = make([]float32, size)
  539. }
  540. added := make([][]int64, 5)
  541. for i := range added {
  542. added[i] = make([]int64, 3)
  543. switch i {
  544. case 0:
  545. added[i][0] = 10
  546. case 1:
  547. added[i][0] = 18
  548. added[i][1] = 2
  549. case 2:
  550. added[i][0] = 12
  551. added[i][1] = 14
  552. case 3:
  553. added[i][0] = 10
  554. added[i][1] = 12
  555. added[i][2] = 6
  556. case 4:
  557. added[i][0] = 8
  558. added[i][1] = 9
  559. added[i][2] = 13
  560. }
  561. }
  562. assert.Panics(t, func() {
  563. daily2 := make([][]float32, 16)
  564. for i := range daily2 {
  565. daily2[i] = make([]float32, 15)
  566. }
  567. addBurndownMatrix(added, 5, 3, daily2, 1)
  568. })
  569. assert.Panics(t, func() {
  570. daily2 := make([][]float32, 15)
  571. for i := range daily2 {
  572. daily2[i] = make([]float32, 16)
  573. }
  574. addBurndownMatrix(added, 5, 3, daily2, 1)
  575. })
  576. // yaml.PrintMatrix(os.Stdout, added, 0, "test", true)
  577. /*
  578. "test": |-
  579. 10 0 0
  580. 18 2 0
  581. 12 14 0
  582. 10 12 6
  583. 8 9 13
  584. */
  585. addBurndownMatrix(added, 5, 3, daily, 1)
  586. for i := range daily[0] {
  587. assert.Equal(t, daily[0][i], float32(0))
  588. }
  589. for i := range daily {
  590. assert.Equal(t, daily[i][0], float32(0))
  591. }
  592. /*for _, row := range daily {
  593. fmt.Println(row)
  594. }*/
  595. // check pinned points
  596. for y := 0; y < 5; y++ {
  597. for x := 0; x < 3; x++ {
  598. var sum float32
  599. for i := x * 5; i < (x+1)*5; i++ {
  600. sum += daily[(y+1)*3][i+1]
  601. }
  602. assert.InDelta(t, sum, added[y][x], 0.00001)
  603. }
  604. }
  605. // check overall trend: 0 -> const -> peak -> decay
  606. for x := 0; x < 15; x++ {
  607. for y := 0; y < x; y++ {
  608. assert.Zero(t, daily[y+1][x+1])
  609. }
  610. var prev float32
  611. for y := x; y < ((x+3)/5)*5; y++ {
  612. if prev == 0 {
  613. prev = daily[y+1][x+1]
  614. }
  615. assert.Equal(t, daily[y+1][x+1], prev)
  616. }
  617. for y := ((x + 3) / 5) * 5; y < 15; y++ {
  618. if prev == 0 {
  619. prev = daily[y+1][x+1]
  620. }
  621. assert.True(t, daily[y+1][x+1] <= prev)
  622. prev = daily[y+1][x+1]
  623. }
  624. }
  625. }
  626. func TestBurndownAddMatrixCrazy(t *testing.T) {
  627. size := 5 * 3
  628. daily := make([][]float32, size)
  629. for i := range daily {
  630. daily[i] = make([]float32, size)
  631. }
  632. added := make([][]int64, 5)
  633. for i := range added {
  634. added[i] = make([]int64, 3)
  635. switch i {
  636. case 0:
  637. added[i][0] = 10
  638. case 1:
  639. added[i][0] = 9
  640. added[i][1] = 2
  641. case 2:
  642. added[i][0] = 8
  643. added[i][1] = 16
  644. case 3:
  645. added[i][0] = 7
  646. added[i][1] = 12
  647. added[i][2] = 6
  648. case 4:
  649. added[i][0] = 6
  650. added[i][1] = 9
  651. added[i][2] = 13
  652. }
  653. }
  654. // yaml.PrintMatrix(os.Stdout, added, 0, "test", true)
  655. /*
  656. "test": |-
  657. 10 0 0
  658. 9 2 0
  659. 8 16 0
  660. 7 12 6
  661. 6 9 13
  662. */
  663. addBurndownMatrix(added, 5, 3, daily, 0)
  664. /*
  665. for _, row := range daily {
  666. for _, v := range row {
  667. fmt.Print(v, " ")
  668. }
  669. fmt.Println()
  670. }
  671. */
  672. // check pinned points
  673. for y := 0; y < 5; y++ {
  674. for x := 0; x < 3; x++ {
  675. var sum float32
  676. for i := x * 5; i < (x+1)*5; i++ {
  677. sum += daily[(y+1)*3-1][i]
  678. }
  679. assert.InDelta(t, sum, added[y][x], 0.00001)
  680. }
  681. }
  682. // check overall trend: 0 -> const -> peak -> decay
  683. for x := 0; x < 15; x++ {
  684. for y := 0; y < x; y++ {
  685. assert.Zero(t, daily[y][x])
  686. }
  687. var prev float32
  688. for y := x; y < ((x+3)/5)*5; y++ {
  689. if prev == 0 {
  690. prev = daily[y][x]
  691. }
  692. assert.Equal(t, daily[y][x], prev)
  693. }
  694. for y := ((x + 3) / 5) * 5; y < 15; y++ {
  695. if prev == 0 {
  696. prev = daily[y][x]
  697. }
  698. assert.True(t, daily[y][x] <= prev)
  699. prev = daily[y][x]
  700. }
  701. }
  702. }
  703. func TestBurndownAddMatrixNaNs(t *testing.T) {
  704. size := 4 * 4
  705. daily := make([][]float32, size)
  706. for i := range daily {
  707. daily[i] = make([]float32, size)
  708. }
  709. added := make([][]int64, 4)
  710. for i := range added {
  711. added[i] = make([]int64, 4)
  712. switch i {
  713. case 0:
  714. added[i][0] = 20
  715. case 1:
  716. added[i][0] = 18
  717. added[i][1] = 30
  718. case 2:
  719. added[i][0] = 15
  720. added[i][1] = 25
  721. added[i][2] = 28
  722. case 3:
  723. added[i][0] = 12
  724. added[i][1] = 20
  725. added[i][2] = 25
  726. added[i][3] = 40
  727. }
  728. }
  729. // yaml.PrintMatrix(os.Stdout, added, 0, "test", true)
  730. /*
  731. "test": |-
  732. 20 0 0 0
  733. 18 30 0 0
  734. 15 25 28 0
  735. 12 20 25 40
  736. */
  737. addBurndownMatrix(added, 4, 4, daily, 0)
  738. /*
  739. for _, row := range daily {
  740. for _, v := range row {
  741. fmt.Print(v, " ")
  742. }
  743. fmt.Println()
  744. }
  745. */
  746. // check pinned points
  747. for y := 0; y < 4; y++ {
  748. for x := 0; x < 4; x++ {
  749. var sum float32
  750. for i := x * 4; i < (x+1)*4; i++ {
  751. sum += daily[(y+1)*4-1][i]
  752. }
  753. assert.InDelta(t, sum, added[y][x], 0.00001)
  754. }
  755. }
  756. // check overall trend: 0 -> const -> peak -> decay
  757. for x := 0; x < 16; x++ {
  758. for y := 0; y < x; y++ {
  759. assert.Zero(t, daily[y][x])
  760. }
  761. var prev float32
  762. for y := x - 4; y < x; y++ {
  763. if y < 0 {
  764. continue
  765. }
  766. if prev == 0 {
  767. prev = daily[y][x]
  768. }
  769. assert.Equal(t, daily[y][x], prev)
  770. }
  771. for y := x; y < 16; y++ {
  772. if prev == 0 {
  773. prev = daily[y][x]
  774. }
  775. assert.True(t, daily[y][x] <= prev)
  776. prev = daily[y][x]
  777. }
  778. }
  779. }
  780. func TestBurndownMergeGlobalHistory(t *testing.T) {
  781. people1 := [...]string{"one", "two"}
  782. res1 := BurndownResult{
  783. GlobalHistory: [][]int64{},
  784. FileHistories: map[string][][]int64{},
  785. PeopleHistories: [][][]int64{},
  786. PeopleMatrix: [][]int64{},
  787. reversedPeopleDict: people1[:],
  788. sampling: 15,
  789. granularity: 20,
  790. }
  791. c1 := CommonAnalysisResult{
  792. BeginTime: 600566400, // 1989 Jan 12
  793. EndTime: 604713600, // 1989 March 1
  794. CommitsNumber: 10,
  795. RunTime: 100000,
  796. }
  797. // 48 days
  798. res1.GlobalHistory = make([][]int64, 48/15+1 /* 4 samples */)
  799. for i := range res1.GlobalHistory {
  800. res1.GlobalHistory[i] = make([]int64, 48/20+1 /* 3 bands */)
  801. switch i {
  802. case 0:
  803. res1.GlobalHistory[i][0] = 1000
  804. case 1:
  805. res1.GlobalHistory[i][0] = 1100
  806. res1.GlobalHistory[i][1] = 400
  807. case 2:
  808. res1.GlobalHistory[i][0] = 900
  809. res1.GlobalHistory[i][1] = 750
  810. res1.GlobalHistory[i][2] = 100
  811. case 3:
  812. res1.GlobalHistory[i][0] = 850
  813. res1.GlobalHistory[i][1] = 700
  814. res1.GlobalHistory[i][2] = 150
  815. }
  816. }
  817. res1.FileHistories["file1"] = res1.GlobalHistory
  818. res1.FileHistories["file2"] = res1.GlobalHistory
  819. res1.PeopleHistories = append(res1.PeopleHistories, res1.GlobalHistory)
  820. res1.PeopleHistories = append(res1.PeopleHistories, res1.GlobalHistory)
  821. res1.PeopleMatrix = append(res1.PeopleMatrix, make([]int64, 4))
  822. res1.PeopleMatrix = append(res1.PeopleMatrix, make([]int64, 4))
  823. res1.PeopleMatrix[0][0] = 10
  824. res1.PeopleMatrix[0][1] = 20
  825. res1.PeopleMatrix[0][2] = 30
  826. res1.PeopleMatrix[0][3] = 40
  827. res1.PeopleMatrix[1][0] = 50
  828. res1.PeopleMatrix[1][1] = 60
  829. res1.PeopleMatrix[1][2] = 70
  830. res1.PeopleMatrix[1][3] = 80
  831. people2 := [...]string{"two", "three"}
  832. res2 := BurndownResult{
  833. GlobalHistory: [][]int64{},
  834. FileHistories: map[string][][]int64{},
  835. PeopleHistories: [][][]int64{},
  836. PeopleMatrix: [][]int64{},
  837. reversedPeopleDict: people2[:],
  838. sampling: 14,
  839. granularity: 19,
  840. }
  841. c2 := CommonAnalysisResult{
  842. BeginTime: 601084800, // 1989 Jan 18
  843. EndTime: 605923200, // 1989 March 15
  844. CommitsNumber: 10,
  845. RunTime: 100000,
  846. }
  847. // 56 days
  848. res2.GlobalHistory = make([][]int64, 56/14 /* 4 samples */)
  849. for i := range res2.GlobalHistory {
  850. res2.GlobalHistory[i] = make([]int64, 56/19+1 /* 3 bands */)
  851. switch i {
  852. case 0:
  853. res2.GlobalHistory[i][0] = 900
  854. case 1:
  855. res2.GlobalHistory[i][0] = 1100
  856. res2.GlobalHistory[i][1] = 400
  857. case 2:
  858. res2.GlobalHistory[i][0] = 900
  859. res2.GlobalHistory[i][1] = 750
  860. res2.GlobalHistory[i][2] = 100
  861. case 3:
  862. res2.GlobalHistory[i][0] = 800
  863. res2.GlobalHistory[i][1] = 600
  864. res2.GlobalHistory[i][2] = 600
  865. }
  866. }
  867. res2.FileHistories["file2"] = res2.GlobalHistory
  868. res2.FileHistories["file3"] = res2.GlobalHistory
  869. res2.PeopleHistories = append(res2.PeopleHistories, res2.GlobalHistory)
  870. res2.PeopleHistories = append(res2.PeopleHistories, res2.GlobalHistory)
  871. res2.PeopleMatrix = append(res2.PeopleMatrix, make([]int64, 4))
  872. res2.PeopleMatrix = append(res2.PeopleMatrix, make([]int64, 4))
  873. res2.PeopleMatrix[0][0] = 100
  874. res2.PeopleMatrix[0][1] = 200
  875. res2.PeopleMatrix[0][2] = 300
  876. res2.PeopleMatrix[0][3] = 400
  877. res2.PeopleMatrix[1][0] = 500
  878. res2.PeopleMatrix[1][1] = 600
  879. res2.PeopleMatrix[1][2] = 700
  880. res2.PeopleMatrix[1][3] = 800
  881. burndown := BurndownAnalysis{}
  882. merged := burndown.MergeResults(res1, res2, &c1, &c2).(BurndownResult)
  883. assert.Equal(t, merged.granularity, 19)
  884. assert.Equal(t, merged.sampling, 14)
  885. assert.Len(t, merged.GlobalHistory, 5)
  886. for _, row := range merged.GlobalHistory {
  887. assert.Len(t, row, 4)
  888. }
  889. assert.Equal(t, merged.FileHistories["file1"], res1.GlobalHistory)
  890. assert.Equal(t, merged.FileHistories["file2"], merged.GlobalHistory)
  891. assert.Equal(t, merged.FileHistories["file3"], res2.GlobalHistory)
  892. assert.Len(t, merged.reversedPeopleDict, 3)
  893. assert.Equal(t, merged.PeopleHistories[0], res1.GlobalHistory)
  894. assert.Equal(t, merged.PeopleHistories[1], merged.GlobalHistory)
  895. assert.Equal(t, merged.PeopleHistories[2], res2.GlobalHistory)
  896. assert.Len(t, merged.PeopleMatrix, 3)
  897. for _, row := range merged.PeopleMatrix {
  898. assert.Len(t, row, 5)
  899. }
  900. assert.Equal(t, merged.PeopleMatrix[0][0], int64(10))
  901. assert.Equal(t, merged.PeopleMatrix[0][1], int64(20))
  902. assert.Equal(t, merged.PeopleMatrix[0][2], int64(30))
  903. assert.Equal(t, merged.PeopleMatrix[0][3], int64(40))
  904. assert.Equal(t, merged.PeopleMatrix[0][4], int64(0))
  905. assert.Equal(t, merged.PeopleMatrix[1][0], int64(150))
  906. assert.Equal(t, merged.PeopleMatrix[1][1], int64(260))
  907. assert.Equal(t, merged.PeopleMatrix[1][2], int64(70))
  908. assert.Equal(t, merged.PeopleMatrix[1][3], int64(380))
  909. assert.Equal(t, merged.PeopleMatrix[1][4], int64(400))
  910. assert.Equal(t, merged.PeopleMatrix[2][0], int64(500))
  911. assert.Equal(t, merged.PeopleMatrix[2][1], int64(600))
  912. assert.Equal(t, merged.PeopleMatrix[2][2], int64(0))
  913. assert.Equal(t, merged.PeopleMatrix[2][3], int64(700))
  914. assert.Equal(t, merged.PeopleMatrix[2][4], int64(800))
  915. burndown.serializeBinary(&merged, ioutil.Discard)
  916. }
  917. func TestBurndownMergeNils(t *testing.T) {
  918. res1 := BurndownResult{
  919. GlobalHistory: [][]int64{},
  920. FileHistories: map[string][][]int64{},
  921. PeopleHistories: [][][]int64{},
  922. PeopleMatrix: [][]int64{},
  923. reversedPeopleDict: []string{},
  924. sampling: 15,
  925. granularity: 20,
  926. }
  927. c1 := CommonAnalysisResult{
  928. BeginTime: 600566400, // 1989 Jan 12
  929. EndTime: 604713600, // 1989 March 1
  930. CommitsNumber: 10,
  931. RunTime: 100000,
  932. }
  933. res2 := BurndownResult{
  934. GlobalHistory: nil,
  935. FileHistories: nil,
  936. PeopleHistories: nil,
  937. PeopleMatrix: nil,
  938. reversedPeopleDict: nil,
  939. sampling: 14,
  940. granularity: 19,
  941. }
  942. c2 := CommonAnalysisResult{
  943. BeginTime: 601084800, // 1989 Jan 18
  944. EndTime: 605923200, // 1989 March 15
  945. CommitsNumber: 10,
  946. RunTime: 100000,
  947. }
  948. burndown := BurndownAnalysis{}
  949. merged := burndown.MergeResults(res1, res2, &c1, &c2).(BurndownResult)
  950. assert.Equal(t, merged.granularity, 19)
  951. assert.Equal(t, merged.sampling, 14)
  952. assert.Nil(t, merged.GlobalHistory)
  953. assert.Nil(t, merged.FileHistories)
  954. assert.Nil(t, merged.PeopleHistories)
  955. assert.Nil(t, merged.PeopleMatrix)
  956. burndown.serializeBinary(&merged, ioutil.Discard)
  957. res2.GlobalHistory = make([][]int64, 56/14 /* 4 samples */)
  958. for i := range res2.GlobalHistory {
  959. res2.GlobalHistory[i] = make([]int64, 56/19+1 /* 3 bands */)
  960. switch i {
  961. case 0:
  962. res2.GlobalHistory[i][0] = 900
  963. case 1:
  964. res2.GlobalHistory[i][0] = 1100
  965. res2.GlobalHistory[i][1] = 400
  966. case 2:
  967. res2.GlobalHistory[i][0] = 900
  968. res2.GlobalHistory[i][1] = 750
  969. res2.GlobalHistory[i][2] = 100
  970. case 3:
  971. res2.GlobalHistory[i][0] = 800
  972. res2.GlobalHistory[i][1] = 600
  973. res2.GlobalHistory[i][2] = 600
  974. }
  975. }
  976. people1 := [...]string{"one", "two"}
  977. res1.reversedPeopleDict = people1[:]
  978. res1.PeopleMatrix = append(res1.PeopleMatrix, make([]int64, 4))
  979. res1.PeopleMatrix = append(res1.PeopleMatrix, make([]int64, 4))
  980. res1.PeopleMatrix[0][0] = 10
  981. res1.PeopleMatrix[0][1] = 20
  982. res1.PeopleMatrix[0][2] = 30
  983. res1.PeopleMatrix[0][3] = 40
  984. res1.PeopleMatrix[1][0] = 50
  985. res1.PeopleMatrix[1][1] = 60
  986. res1.PeopleMatrix[1][2] = 70
  987. res1.PeopleMatrix[1][3] = 80
  988. people2 := [...]string{"two", "three"}
  989. res2.reversedPeopleDict = people2[:]
  990. merged = burndown.MergeResults(res1, res2, &c1, &c2).(BurndownResult)
  991. mgh := [5][4]int64{
  992. {0, 0, 0, 0},
  993. {578, 0, 0, 0},
  994. {798, 546, 0, 0},
  995. {664, 884, 222, 0},
  996. {547, 663, 610, 178},
  997. }
  998. mgh2 := [...][]int64{
  999. mgh[0][:], mgh[1][:], mgh[2][:], mgh[3][:], mgh[4][:],
  1000. }
  1001. mgh3 := mgh2[:]
  1002. assert.Equal(t, mgh3, merged.GlobalHistory)
  1003. assert.Len(t, merged.PeopleMatrix, 3)
  1004. for _, row := range merged.PeopleMatrix {
  1005. assert.Len(t, row, 5)
  1006. }
  1007. assert.Equal(t, merged.PeopleMatrix[0][0], int64(10))
  1008. assert.Equal(t, merged.PeopleMatrix[0][1], int64(20))
  1009. assert.Equal(t, merged.PeopleMatrix[0][2], int64(30))
  1010. assert.Equal(t, merged.PeopleMatrix[0][3], int64(40))
  1011. assert.Equal(t, merged.PeopleMatrix[0][4], int64(0))
  1012. assert.Equal(t, merged.PeopleMatrix[1][0], int64(50))
  1013. assert.Equal(t, merged.PeopleMatrix[1][1], int64(60))
  1014. assert.Equal(t, merged.PeopleMatrix[1][2], int64(70))
  1015. assert.Equal(t, merged.PeopleMatrix[1][3], int64(80))
  1016. assert.Equal(t, merged.PeopleMatrix[1][4], int64(0))
  1017. assert.Equal(t, merged.PeopleMatrix[2][0], int64(0))
  1018. assert.Equal(t, merged.PeopleMatrix[2][1], int64(0))
  1019. assert.Equal(t, merged.PeopleMatrix[2][2], int64(0))
  1020. assert.Equal(t, merged.PeopleMatrix[2][3], int64(0))
  1021. assert.Equal(t, merged.PeopleMatrix[2][4], int64(0))
  1022. burndown.serializeBinary(&merged, ioutil.Discard)
  1023. }
  1024. func TestBurndownDeserialize(t *testing.T) {
  1025. allBuffer, err := ioutil.ReadFile(path.Join("test_data", "burndown.pb"))
  1026. assert.Nil(t, err)
  1027. message := pb.AnalysisResults{}
  1028. err = proto.Unmarshal(allBuffer, &message)
  1029. assert.Nil(t, err)
  1030. burndown := BurndownAnalysis{}
  1031. iresult, err := burndown.Deserialize(message.Contents[burndown.Name()])
  1032. assert.Nil(t, err)
  1033. result := iresult.(BurndownResult)
  1034. assert.True(t, len(result.GlobalHistory) > 0)
  1035. assert.True(t, len(result.FileHistories) > 0)
  1036. assert.True(t, len(result.reversedPeopleDict) > 0)
  1037. assert.True(t, len(result.PeopleHistories) > 0)
  1038. assert.True(t, len(result.PeopleMatrix) > 0)
  1039. assert.Equal(t, result.granularity, 30)
  1040. assert.Equal(t, result.sampling, 30)
  1041. }