|
@@ -0,0 +1,303 @@
|
|
|
+package hercules
|
|
|
+
|
|
|
+import (
|
|
|
+ "io/ioutil"
|
|
|
+ "path"
|
|
|
+ "testing"
|
|
|
+
|
|
|
+ "bytes"
|
|
|
+ "github.com/gogo/protobuf/proto"
|
|
|
+ "github.com/sergi/go-diff/diffmatchpatch"
|
|
|
+ "github.com/stretchr/testify/assert"
|
|
|
+ "gopkg.in/bblfsh/sdk.v1/uast"
|
|
|
+ "gopkg.in/src-d/go-git.v4/plumbing/object"
|
|
|
+ "gopkg.in/src-d/hercules.v3/pb"
|
|
|
+)
|
|
|
+
|
|
|
+func fixtureShotness() *ShotnessAnalysis {
|
|
|
+ sh := &ShotnessAnalysis{}
|
|
|
+ sh.Initialize(testRepository)
|
|
|
+ sh.Configure(nil)
|
|
|
+ return sh
|
|
|
+}
|
|
|
+
|
|
|
+func TestShotnessMeta(t *testing.T) {
|
|
|
+ sh := &ShotnessAnalysis{}
|
|
|
+ sh.Initialize(testRepository)
|
|
|
+ assert.NotNil(t, sh.nodes)
|
|
|
+ assert.NotNil(t, sh.files)
|
|
|
+ assert.Equal(t, sh.Name(), "Shotness")
|
|
|
+ assert.Len(t, sh.Provides(), 0)
|
|
|
+ assert.Equal(t, len(sh.Requires()), 2)
|
|
|
+ assert.Equal(t, sh.Requires()[0], DependencyFileDiff)
|
|
|
+ assert.Equal(t, sh.Requires()[1], DependencyUastChanges)
|
|
|
+ assert.Len(t, sh.ListConfigurationOptions(), 2)
|
|
|
+ assert.Equal(t, sh.ListConfigurationOptions()[0].Name, ConfigShotnessXpathStruct)
|
|
|
+ assert.Equal(t, sh.ListConfigurationOptions()[1].Name, ConfigShotnessXpathName)
|
|
|
+ sh.Configure(nil)
|
|
|
+ assert.Equal(t, sh.XpathStruct, DefaultShotnessXpathStruct)
|
|
|
+ assert.Equal(t, sh.XpathName, DefaultShotnessXpathName)
|
|
|
+ facts := map[string]interface{}{}
|
|
|
+ facts[ConfigShotnessXpathStruct] = "xpath!"
|
|
|
+ facts[ConfigShotnessXpathName] = "another!"
|
|
|
+ sh.Configure(facts)
|
|
|
+ assert.Equal(t, sh.XpathStruct, "xpath!")
|
|
|
+ assert.Equal(t, sh.XpathName, "another!")
|
|
|
+ features := sh.Features()
|
|
|
+ assert.Len(t, features, 1)
|
|
|
+ assert.Equal(t, features[0], FeatureUast)
|
|
|
+}
|
|
|
+
|
|
|
+func TestShotnessRegistration(t *testing.T) {
|
|
|
+ tp, exists := Registry.registered[(&ShotnessAnalysis{}).Name()]
|
|
|
+ assert.True(t, exists)
|
|
|
+ assert.Equal(t, tp.Elem().Name(), "ShotnessAnalysis")
|
|
|
+ tp, exists = Registry.flags[(&ShotnessAnalysis{}).Flag()]
|
|
|
+ assert.True(t, exists)
|
|
|
+ assert.Equal(t, tp.Elem().Name(), "ShotnessAnalysis")
|
|
|
+}
|
|
|
+
|
|
|
+func bakeShotness(t *testing.T) (*ShotnessAnalysis, ShotnessAnalysisResult) {
|
|
|
+ sh := fixtureShotness()
|
|
|
+ bytes1, err := ioutil.ReadFile(path.Join("test_data", "1.java"))
|
|
|
+ assert.Nil(t, err)
|
|
|
+ bytes2, err := ioutil.ReadFile(path.Join("test_data", "2.java"))
|
|
|
+ assert.Nil(t, err)
|
|
|
+ dmp := diffmatchpatch.New()
|
|
|
+ src, dst, _ := dmp.DiffLinesToRunes(string(bytes1), string(bytes2))
|
|
|
+ state := map[string]interface{}{}
|
|
|
+ state["commit"] = &object.Commit{}
|
|
|
+ fileDiffs := map[string]FileDiffData{}
|
|
|
+ const fileName = "test.java"
|
|
|
+ fileDiffs[fileName] = FileDiffData{
|
|
|
+ OldLinesOfCode: len(src),
|
|
|
+ NewLinesOfCode: len(dst),
|
|
|
+ Diffs: dmp.DiffMainRunes(src, dst, false),
|
|
|
+ }
|
|
|
+ state[DependencyFileDiff] = fileDiffs
|
|
|
+ uastChanges := make([]UASTChange, 1)
|
|
|
+ loadUast := func(name string) *uast.Node {
|
|
|
+ bytes, err := ioutil.ReadFile(path.Join("test_data", name))
|
|
|
+ assert.Nil(t, err)
|
|
|
+ node := uast.Node{}
|
|
|
+ proto.Unmarshal(bytes, &node)
|
|
|
+ return &node
|
|
|
+ }
|
|
|
+ state[DependencyUastChanges] = uastChanges
|
|
|
+ uastChanges[0] = UASTChange{
|
|
|
+ Change: &object.Change{
|
|
|
+ From: object.ChangeEntry{},
|
|
|
+ To: object.ChangeEntry{Name: fileName}},
|
|
|
+ Before: nil, After: loadUast("uast1.pb"),
|
|
|
+ }
|
|
|
+ iresult, err := sh.Consume(state)
|
|
|
+ assert.Nil(t, err)
|
|
|
+ assert.Nil(t, iresult)
|
|
|
+ uastChanges[0] = UASTChange{
|
|
|
+ Change: &object.Change{
|
|
|
+ From: object.ChangeEntry{Name: fileName},
|
|
|
+ To: object.ChangeEntry{Name: fileName}},
|
|
|
+ Before: loadUast("uast1.pb"), After: loadUast("uast2.pb"),
|
|
|
+ }
|
|
|
+ iresult, err = sh.Consume(state)
|
|
|
+ assert.Nil(t, err)
|
|
|
+ assert.Nil(t, iresult)
|
|
|
+ return sh, sh.Finalize().(ShotnessAnalysisResult)
|
|
|
+}
|
|
|
+
|
|
|
+func TestShotnessConsume(t *testing.T) {
|
|
|
+ sh := fixtureShotness()
|
|
|
+ bytes1, err := ioutil.ReadFile(path.Join("test_data", "1.java"))
|
|
|
+ assert.Nil(t, err)
|
|
|
+ bytes2, err := ioutil.ReadFile(path.Join("test_data", "2.java"))
|
|
|
+ assert.Nil(t, err)
|
|
|
+ dmp := diffmatchpatch.New()
|
|
|
+ src, dst, _ := dmp.DiffLinesToRunes(string(bytes1), string(bytes2))
|
|
|
+ state := map[string]interface{}{}
|
|
|
+ state["commit"] = &object.Commit{}
|
|
|
+ fileDiffs := map[string]FileDiffData{}
|
|
|
+ const fileName = "test.java"
|
|
|
+ const newfileName = "new.java"
|
|
|
+ fileDiffs[fileName] = FileDiffData{
|
|
|
+ OldLinesOfCode: len(src),
|
|
|
+ NewLinesOfCode: len(dst),
|
|
|
+ Diffs: dmp.DiffMainRunes(src, dst, false),
|
|
|
+ }
|
|
|
+ state[DependencyFileDiff] = fileDiffs
|
|
|
+ uastChanges := make([]UASTChange, 1)
|
|
|
+ loadUast := func(name string) *uast.Node {
|
|
|
+ bytes, err := ioutil.ReadFile(path.Join("test_data", name))
|
|
|
+ assert.Nil(t, err)
|
|
|
+ node := uast.Node{}
|
|
|
+ proto.Unmarshal(bytes, &node)
|
|
|
+ return &node
|
|
|
+ }
|
|
|
+ state[DependencyUastChanges] = uastChanges
|
|
|
+ uastChanges[0] = UASTChange{
|
|
|
+ Change: &object.Change{
|
|
|
+ From: object.ChangeEntry{},
|
|
|
+ To: object.ChangeEntry{Name: fileName}},
|
|
|
+ Before: nil, After: loadUast("uast1.pb"),
|
|
|
+ }
|
|
|
+ iresult, err := sh.Consume(state)
|
|
|
+ assert.Nil(t, err)
|
|
|
+ assert.Nil(t, iresult)
|
|
|
+ uastChanges[0] = UASTChange{
|
|
|
+ Change: &object.Change{
|
|
|
+ From: object.ChangeEntry{Name: fileName},
|
|
|
+ To: object.ChangeEntry{Name: newfileName}},
|
|
|
+ Before: loadUast("uast1.pb"), After: loadUast("uast2.pb"),
|
|
|
+ }
|
|
|
+ fileDiffs[newfileName] = fileDiffs[fileName]
|
|
|
+ delete(fileDiffs, fileName)
|
|
|
+ iresult, err = sh.Consume(state)
|
|
|
+ assert.Nil(t, err)
|
|
|
+ assert.Nil(t, iresult)
|
|
|
+ assert.Len(t, sh.nodes, 18)
|
|
|
+ assert.Len(t, sh.files, 1)
|
|
|
+ assert.Len(t, sh.files["new.java"], 18)
|
|
|
+ for _, node := range sh.nodes {
|
|
|
+ assert.Equal(t, node.Summary.InternalRole, "MethodDeclaration")
|
|
|
+ if node.Summary.Name != "testUnpackEntryFromFile" {
|
|
|
+ assert.Equal(t, node.Count, 1)
|
|
|
+ if node.Summary.Name != "testUnpackEntryFromStreamToFile" {
|
|
|
+ assert.Len(t, node.Couples, 16)
|
|
|
+ } else {
|
|
|
+ assert.Len(t, node.Couples, 1)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ assert.Equal(t, node.Count, 2)
|
|
|
+ assert.Len(t, node.Couples, 17)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result := sh.Finalize().(ShotnessAnalysisResult)
|
|
|
+ assert.Len(t, result.Nodes, 18)
|
|
|
+ assert.Len(t, result.Counters, 18)
|
|
|
+ assert.Equal(t, result.Nodes[14].String(),
|
|
|
+ "MethodDeclaration_testUnpackEntryFromStreamToFile_"+newfileName)
|
|
|
+ assert.Equal(t, result.Counters[14], map[int]int{14: 1, 13: 1})
|
|
|
+ assert.Equal(t, result.Nodes[15].String(),
|
|
|
+ "MethodDeclaration_testUnpackEntryFromStream_"+newfileName)
|
|
|
+ assert.Equal(t, result.Counters[15], map[int]int{
|
|
|
+ 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})
|
|
|
+ uastChanges[0] = UASTChange{
|
|
|
+ Change: &object.Change{
|
|
|
+ From: object.ChangeEntry{Name: newfileName},
|
|
|
+ To: object.ChangeEntry{}},
|
|
|
+ Before: loadUast("uast2.pb"), After: nil,
|
|
|
+ }
|
|
|
+ iresult, err = sh.Consume(state)
|
|
|
+ assert.Nil(t, err)
|
|
|
+ assert.Nil(t, iresult)
|
|
|
+ assert.Len(t, sh.nodes, 0)
|
|
|
+ assert.Len(t, sh.files, 0)
|
|
|
+}
|
|
|
+
|
|
|
+func TestShotnessSerializeText(t *testing.T) {
|
|
|
+ sh, result := bakeShotness(t)
|
|
|
+ buffer := &bytes.Buffer{}
|
|
|
+ sh.Serialize(result, false, buffer)
|
|
|
+ assert.Equal(t, buffer.String(), ` - name: testAddEntry
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testArchiveEquals
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testContainsAnyEntry
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testDuplicateEntryAtAddOrReplace
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testDuplicateEntryAtAdd
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testDuplicateEntryAtReplace
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testPackEntries
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testPackEntry
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testPreserveRoot
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testRemoveDirs
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testRemoveEntry
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testRepackArchive
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testUnexplode
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testUnpackEntryFromFile
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testUnpackEntryFromStreamToFile
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ counters: {13:1,14:1}
|
|
|
+ - name: testUnpackEntryFromStream
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: testZipException
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,59,41,45]
|
|
|
+ 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}
|
|
|
+ - name: unexplodeWithException
|
|
|
+ file: test.java
|
|
|
+ ir: MethodDeclaration
|
|
|
+ roles: [111,100,41,45]
|
|
|
+ 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}
|
|
|
+`)
|
|
|
+}
|
|
|
+
|
|
|
+func TestShotnessSerializeBinary(t *testing.T) {
|
|
|
+ sh, result := bakeShotness(t)
|
|
|
+ buffer := &bytes.Buffer{}
|
|
|
+ sh.Serialize(result, true, buffer)
|
|
|
+ message := pb.ShotnessAnalysisResultMessage{}
|
|
|
+ err := proto.Unmarshal(buffer.Bytes(), &message)
|
|
|
+ assert.Nil(t, err)
|
|
|
+ assert.Len(t, message.Records, 18)
|
|
|
+ assert.Equal(t, message.Records[14].Name, "testUnpackEntryFromStreamToFile")
|
|
|
+ assert.Equal(t, message.Records[14].Counters, map[int32]int32{14: 1, 13: 1})
|
|
|
+}
|