shotness_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. package leaves
  2. import (
  3. "io/ioutil"
  4. "path"
  5. "testing"
  6. "bytes"
  7. "github.com/gogo/protobuf/proto"
  8. "github.com/sergi/go-diff/diffmatchpatch"
  9. "github.com/stretchr/testify/assert"
  10. "gopkg.in/bblfsh/sdk.v1/uast"
  11. "gopkg.in/src-d/go-git.v4/plumbing/object"
  12. "gopkg.in/src-d/hercules.v4/internal/core"
  13. "gopkg.in/src-d/hercules.v4/internal/pb"
  14. items "gopkg.in/src-d/hercules.v4/internal/plumbing"
  15. uast_items "gopkg.in/src-d/hercules.v4/internal/plumbing/uast"
  16. "gopkg.in/src-d/hercules.v4/internal/test"
  17. )
  18. func fixtureShotness() *ShotnessAnalysis {
  19. sh := &ShotnessAnalysis{}
  20. sh.Initialize(test.Repository)
  21. sh.Configure(nil)
  22. return sh
  23. }
  24. func TestShotnessMeta(t *testing.T) {
  25. sh := &ShotnessAnalysis{}
  26. sh.Initialize(test.Repository)
  27. assert.NotNil(t, sh.nodes)
  28. assert.NotNil(t, sh.files)
  29. assert.Equal(t, sh.Name(), "Shotness")
  30. assert.Len(t, sh.Provides(), 0)
  31. assert.Equal(t, len(sh.Requires()), 2)
  32. assert.Equal(t, sh.Requires()[0], items.DependencyFileDiff)
  33. assert.Equal(t, sh.Requires()[1], uast_items.DependencyUastChanges)
  34. assert.Len(t, sh.ListConfigurationOptions(), 2)
  35. assert.Equal(t, sh.ListConfigurationOptions()[0].Name, ConfigShotnessXpathStruct)
  36. assert.Equal(t, sh.ListConfigurationOptions()[1].Name, ConfigShotnessXpathName)
  37. sh.Configure(nil)
  38. assert.Equal(t, sh.XpathStruct, DefaultShotnessXpathStruct)
  39. assert.Equal(t, sh.XpathName, DefaultShotnessXpathName)
  40. facts := map[string]interface{}{}
  41. facts[ConfigShotnessXpathStruct] = "xpath!"
  42. facts[ConfigShotnessXpathName] = "another!"
  43. sh.Configure(facts)
  44. assert.Equal(t, sh.XpathStruct, "xpath!")
  45. assert.Equal(t, sh.XpathName, "another!")
  46. features := sh.Features()
  47. assert.Len(t, features, 1)
  48. assert.Equal(t, features[0], uast_items.FeatureUast)
  49. }
  50. func TestShotnessRegistration(t *testing.T) {
  51. summoned := core.Registry.Summon((&ShotnessAnalysis{}).Name())
  52. assert.Len(t, summoned, 1)
  53. assert.Equal(t, summoned[0].Name(), "Shotness")
  54. leaves := core.Registry.GetLeaves()
  55. matched := false
  56. for _, tp := range leaves {
  57. if tp.Flag() == (&ShotnessAnalysis{}).Flag() {
  58. matched = true
  59. break
  60. }
  61. }
  62. assert.True(t, matched)
  63. }
  64. func bakeShotness(t *testing.T, eraseEndPosition bool) (*ShotnessAnalysis, ShotnessResult) {
  65. sh := fixtureShotness()
  66. bytes1, err := ioutil.ReadFile(path.Join("..", "internal", "test_data", "1.java"))
  67. assert.Nil(t, err)
  68. bytes2, err := ioutil.ReadFile(path.Join("..", "internal", "test_data", "2.java"))
  69. assert.Nil(t, err)
  70. dmp := diffmatchpatch.New()
  71. src, dst, _ := dmp.DiffLinesToRunes(string(bytes1), string(bytes2))
  72. state := map[string]interface{}{}
  73. state[core.DependencyCommit] = &object.Commit{}
  74. fileDiffs := map[string]items.FileDiffData{}
  75. const fileName = "test.java"
  76. fileDiffs[fileName] = items.FileDiffData{
  77. OldLinesOfCode: len(src),
  78. NewLinesOfCode: len(dst),
  79. Diffs: dmp.DiffMainRunes(src, dst, false),
  80. }
  81. state[items.DependencyFileDiff] = fileDiffs
  82. uastChanges := make([]uast_items.Change, 1)
  83. loadUast := func(name string) *uast.Node {
  84. bytes, err := ioutil.ReadFile(path.Join("..", "internal", "test_data", name))
  85. assert.Nil(t, err)
  86. node := uast.Node{}
  87. proto.Unmarshal(bytes, &node)
  88. if eraseEndPosition {
  89. uast_items.VisitEachNode(&node, func(child *uast.Node) {
  90. child.EndPosition = nil
  91. })
  92. }
  93. return &node
  94. }
  95. state[uast_items.DependencyUastChanges] = uastChanges
  96. uastChanges[0] = uast_items.Change{
  97. Change: &object.Change{
  98. From: object.ChangeEntry{},
  99. To: object.ChangeEntry{Name: fileName}},
  100. Before: nil, After: loadUast("uast1.pb"),
  101. }
  102. iresult, err := sh.Consume(state)
  103. assert.Nil(t, err)
  104. assert.Nil(t, iresult)
  105. uastChanges[0] = uast_items.Change{
  106. Change: &object.Change{
  107. From: object.ChangeEntry{Name: fileName},
  108. To: object.ChangeEntry{Name: fileName}},
  109. Before: loadUast("uast1.pb"), After: loadUast("uast2.pb"),
  110. }
  111. iresult, err = sh.Consume(state)
  112. assert.Nil(t, err)
  113. assert.Nil(t, iresult)
  114. return sh, sh.Finalize().(ShotnessResult)
  115. }
  116. func TestShotnessConsume(t *testing.T) {
  117. sh := fixtureShotness()
  118. bytes1, err := ioutil.ReadFile(path.Join("..", "internal", "test_data", "1.java"))
  119. assert.Nil(t, err)
  120. bytes2, err := ioutil.ReadFile(path.Join("..", "internal", "test_data", "2.java"))
  121. assert.Nil(t, err)
  122. dmp := diffmatchpatch.New()
  123. src, dst, _ := dmp.DiffLinesToRunes(string(bytes1), string(bytes2))
  124. state := map[string]interface{}{}
  125. state[core.DependencyCommit] = &object.Commit{}
  126. fileDiffs := map[string]items.FileDiffData{}
  127. const fileName = "test.java"
  128. const newfileName = "new.java"
  129. fileDiffs[fileName] = items.FileDiffData{
  130. OldLinesOfCode: len(src),
  131. NewLinesOfCode: len(dst),
  132. Diffs: dmp.DiffMainRunes(src, dst, false),
  133. }
  134. state[items.DependencyFileDiff] = fileDiffs
  135. uastChanges := make([]uast_items.Change, 1)
  136. loadUast := func(name string) *uast.Node {
  137. bytes, err := ioutil.ReadFile(path.Join("..", "internal", "test_data", name))
  138. assert.Nil(t, err)
  139. node := uast.Node{}
  140. proto.Unmarshal(bytes, &node)
  141. return &node
  142. }
  143. state[uast_items.DependencyUastChanges] = uastChanges
  144. uastChanges[0] = uast_items.Change{
  145. Change: &object.Change{
  146. From: object.ChangeEntry{},
  147. To: object.ChangeEntry{Name: fileName}},
  148. Before: nil, After: loadUast("uast1.pb"),
  149. }
  150. iresult, err := sh.Consume(state)
  151. assert.Nil(t, err)
  152. assert.Nil(t, iresult)
  153. uastChanges[0] = uast_items.Change{
  154. Change: &object.Change{
  155. From: object.ChangeEntry{Name: fileName},
  156. To: object.ChangeEntry{Name: newfileName}},
  157. Before: loadUast("uast1.pb"), After: loadUast("uast2.pb"),
  158. }
  159. fileDiffs[newfileName] = fileDiffs[fileName]
  160. delete(fileDiffs, fileName)
  161. iresult, err = sh.Consume(state)
  162. assert.Nil(t, err)
  163. assert.Nil(t, iresult)
  164. assert.Len(t, sh.nodes, 18)
  165. assert.Len(t, sh.files, 1)
  166. assert.Len(t, sh.files["new.java"], 18)
  167. for _, node := range sh.nodes {
  168. assert.Equal(t, node.Summary.InternalRole, "MethodDeclaration")
  169. if node.Summary.Name != "testUnpackEntryFromFile" {
  170. assert.Equal(t, node.Count, 1)
  171. if node.Summary.Name != "testUnpackEntryFromStreamToFile" {
  172. assert.Len(t, node.Couples, 16)
  173. } else {
  174. assert.Len(t, node.Couples, 1)
  175. }
  176. } else {
  177. assert.Equal(t, node.Count, 2)
  178. assert.Len(t, node.Couples, 17)
  179. }
  180. }
  181. result := sh.Finalize().(ShotnessResult)
  182. assert.Len(t, result.Nodes, 18)
  183. assert.Len(t, result.Counters, 18)
  184. assert.Equal(t, result.Nodes[14].String(),
  185. "MethodDeclaration_testUnpackEntryFromStreamToFile_"+newfileName)
  186. assert.Equal(t, result.Counters[14], map[int]int{14: 1, 13: 1})
  187. assert.Equal(t, result.Nodes[15].String(),
  188. "MethodDeclaration_testUnpackEntryFromStream_"+newfileName)
  189. assert.Equal(t, result.Counters[15], map[int]int{
  190. 8: 1, 0: 1, 5: 1, 6: 1, 11: 1, 1: 1, 13: 1, 17: 1, 3: 1, 15: 1, 9: 1, 4: 1, 7: 1, 16: 1, 2: 1, 12: 1, 10: 1})
  191. uastChanges[0] = uast_items.Change{
  192. Change: &object.Change{
  193. From: object.ChangeEntry{Name: newfileName},
  194. To: object.ChangeEntry{}},
  195. Before: loadUast("uast2.pb"), After: nil,
  196. }
  197. iresult, err = sh.Consume(state)
  198. assert.Nil(t, err)
  199. assert.Nil(t, iresult)
  200. assert.Len(t, sh.nodes, 0)
  201. assert.Len(t, sh.files, 0)
  202. }
  203. func TestShotnessFork(t *testing.T) {
  204. sh1 := fixtureShotness()
  205. clones := sh1.Fork(1)
  206. assert.Len(t, clones, 1)
  207. sh2 := clones[0].(*ShotnessAnalysis)
  208. assert.True(t, sh1 == sh2)
  209. sh1.Merge([]core.PipelineItem{sh2})
  210. }
  211. func TestShotnessConsumeNoEnd(t *testing.T) {
  212. _, result1 := bakeShotness(t, false)
  213. _, result2 := bakeShotness(t, true)
  214. assert.Equal(t, result1, result2)
  215. }
  216. func TestShotnessSerializeText(t *testing.T) {
  217. sh, result := bakeShotness(t, false)
  218. buffer := &bytes.Buffer{}
  219. sh.Serialize(result, false, buffer)
  220. assert.Equal(t, buffer.String(), ` - name: testAddEntry
  221. file: test.java
  222. internal_role: MethodDeclaration
  223. roles: [111,59,41,45]
  224. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  225. - name: testArchiveEquals
  226. file: test.java
  227. internal_role: MethodDeclaration
  228. roles: [111,59,41,45]
  229. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  230. - name: testContainsAnyEntry
  231. file: test.java
  232. internal_role: MethodDeclaration
  233. roles: [111,59,41,45]
  234. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  235. - name: testDuplicateEntryAtAddOrReplace
  236. file: test.java
  237. internal_role: MethodDeclaration
  238. roles: [111,59,41,45]
  239. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  240. - name: testDuplicateEntryAtAdd
  241. file: test.java
  242. internal_role: MethodDeclaration
  243. roles: [111,59,41,45]
  244. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  245. - name: testDuplicateEntryAtReplace
  246. file: test.java
  247. internal_role: MethodDeclaration
  248. roles: [111,59,41,45]
  249. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  250. - name: testPackEntries
  251. file: test.java
  252. internal_role: MethodDeclaration
  253. roles: [111,59,41,45]
  254. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  255. - name: testPackEntry
  256. file: test.java
  257. internal_role: MethodDeclaration
  258. roles: [111,59,41,45]
  259. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  260. - name: testPreserveRoot
  261. file: test.java
  262. internal_role: MethodDeclaration
  263. roles: [111,59,41,45]
  264. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  265. - name: testRemoveDirs
  266. file: test.java
  267. internal_role: MethodDeclaration
  268. roles: [111,59,41,45]
  269. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  270. - name: testRemoveEntry
  271. file: test.java
  272. internal_role: MethodDeclaration
  273. roles: [111,59,41,45]
  274. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  275. - name: testRepackArchive
  276. file: test.java
  277. internal_role: MethodDeclaration
  278. roles: [111,59,41,45]
  279. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  280. - name: testUnexplode
  281. file: test.java
  282. internal_role: MethodDeclaration
  283. roles: [111,59,41,45]
  284. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  285. - name: testUnpackEntryFromFile
  286. file: test.java
  287. internal_role: MethodDeclaration
  288. roles: [111,59,41,45]
  289. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":2,"14":1,"15":1,"16":1,"17":1}
  290. - name: testUnpackEntryFromStreamToFile
  291. file: test.java
  292. internal_role: MethodDeclaration
  293. roles: [111,59,41,45]
  294. counters: {"13":1,"14":1}
  295. - name: testUnpackEntryFromStream
  296. file: test.java
  297. internal_role: MethodDeclaration
  298. roles: [111,59,41,45]
  299. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  300. - name: testZipException
  301. file: test.java
  302. internal_role: MethodDeclaration
  303. roles: [111,59,41,45]
  304. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  305. - name: unexplodeWithException
  306. file: test.java
  307. internal_role: MethodDeclaration
  308. roles: [111,100,41,45]
  309. counters: {"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"15":1,"16":1,"17":1}
  310. `)
  311. }
  312. func TestShotnessSerializeBinary(t *testing.T) {
  313. sh, result := bakeShotness(t, false)
  314. buffer := &bytes.Buffer{}
  315. sh.Serialize(result, true, buffer)
  316. message := pb.ShotnessAnalysisResults{}
  317. err := proto.Unmarshal(buffer.Bytes(), &message)
  318. assert.Nil(t, err)
  319. assert.Len(t, message.Records, 18)
  320. assert.Equal(t, message.Records[14].Name, "testUnpackEntryFromStreamToFile")
  321. assert.Equal(t, message.Records[14].Counters, map[int32]int32{14: 1, 13: 1})
  322. }