mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-22 09:29:38 +00:00
neotest: POC of test coverage
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
1f62ecd5a3
commit
96b5d90894
4 changed files with 115 additions and 7 deletions
|
@ -335,7 +335,7 @@ func (e *Executor) AddNewBlock(t testing.TB, txs ...*transaction.Transaction) *b
|
|||
return b
|
||||
}
|
||||
|
||||
// GenerateNewBlocks adds the specified number of empty blocks to the chain.
|
||||
// GenerateNewBlocks adds the specified number of empty Blocks to the chain.
|
||||
func (e *Executor) GenerateNewBlocks(t testing.TB, count int) []*block.Block {
|
||||
blocks := make([]*block.Block, count)
|
||||
for i := 0; i < count; i++ {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package neotest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
|
@ -48,8 +49,12 @@ func (e *Executor) ValidatorInvoker(h util.Uint160) *ContractInvoker {
|
|||
|
||||
// TestInvoke creates test the VM and invokes the method with the args.
|
||||
func (c *ContractInvoker) TestInvoke(t testing.TB, method string, args ...interface{}) (*vm.Stack, error) {
|
||||
fmt.Println("TEST INVOKE")
|
||||
tx := c.PrepareInvokeNoSign(t, method, args...)
|
||||
b := c.NewUnsignedBlock(t, tx)
|
||||
|
||||
calculateCoverage(t, c.Chain, tx, b)
|
||||
|
||||
ic := c.Chain.GetTestVM(trigger.Application, tx, b)
|
||||
t.Cleanup(ic.Finalize)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package neotest
|
|||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
||||
|
@ -16,9 +17,10 @@ import (
|
|||
|
||||
// Contract contains contract info for deployment.
|
||||
type Contract struct {
|
||||
Hash util.Uint160
|
||||
NEF *nef.File
|
||||
Manifest *manifest.Manifest
|
||||
Hash util.Uint160
|
||||
NEF *nef.File
|
||||
Manifest *manifest.Manifest
|
||||
DebugInfo *compiler.DebugInfo
|
||||
}
|
||||
|
||||
// contracts caches the compiled contracts from FS across multiple tests.
|
||||
|
@ -44,6 +46,11 @@ func CompileSource(t testing.TB, sender util.Uint160, src io.Reader, opts *compi
|
|||
|
||||
// CompileFile compiles a contract from the file and returns its NEF, manifest and hash.
|
||||
func CompileFile(t testing.TB, sender util.Uint160, srcPath string, configPath string) *Contract {
|
||||
absPath, err := filepath.Abs(srcPath)
|
||||
if err == nil {
|
||||
srcPath = absPath
|
||||
}
|
||||
|
||||
if c, ok := contracts[srcPath]; ok {
|
||||
return c
|
||||
}
|
||||
|
@ -72,9 +79,10 @@ func CompileFile(t testing.TB, sender util.Uint160, srcPath string, configPath s
|
|||
require.NoError(t, err)
|
||||
|
||||
c := &Contract{
|
||||
Hash: state.CreateContractHash(sender, ne.Checksum, m.Name),
|
||||
NEF: ne,
|
||||
Manifest: m,
|
||||
Hash: state.CreateContractHash(sender, ne.Checksum, m.Name),
|
||||
NEF: ne,
|
||||
Manifest: m,
|
||||
DebugInfo: di,
|
||||
}
|
||||
contracts[srcPath] = c
|
||||
return c
|
||||
|
|
95
pkg/neotest/coverage.go
Normal file
95
pkg/neotest/coverage.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
package neotest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
var (
|
||||
Blocks map[string][]testing.CoverBlock
|
||||
Counters map[string][]uint32
|
||||
)
|
||||
|
||||
func init() {
|
||||
var cover testing.Cover
|
||||
cover.Mode = testing.CoverMode()
|
||||
Blocks = make(map[string][]testing.CoverBlock)
|
||||
Counters = make(map[string][]uint32)
|
||||
cover.Blocks = Blocks
|
||||
cover.Counters = Counters
|
||||
testing.RegisterCover(cover)
|
||||
}
|
||||
|
||||
func calculateCoverage(t testing.TB, bc blockchainer.Blockchainer, tx *transaction.Transaction, b *block.Block) {
|
||||
fmt.Println("CALCULATE COVERAGE")
|
||||
ic := bc.GetTestVM(trigger.Application, tx, b)
|
||||
t.Cleanup(ic.Finalize)
|
||||
|
||||
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||
|
||||
hm := make(map[util.Uint160][]int)
|
||||
|
||||
runLoop:
|
||||
for {
|
||||
switch {
|
||||
case ic.VM.HasStopped():
|
||||
break runLoop
|
||||
default:
|
||||
h := ic.VM.GetCurrentScriptHash()
|
||||
if err := ic.VM.Step(); err != nil {
|
||||
break runLoop
|
||||
}
|
||||
if ic.VM.Context() != nil {
|
||||
hm[h] = append(hm[h], ic.VM.Context().IP())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate coverage.
|
||||
coverageLoop:
|
||||
for h := range hm {
|
||||
fmt.Println("TRY HASH", h)
|
||||
for name, c := range contracts {
|
||||
fmt.Println("TRY CONTRACT", name, c.Hash)
|
||||
if !c.Hash.Equals(h) {
|
||||
continue
|
||||
}
|
||||
if c.DebugInfo == nil {
|
||||
continue coverageLoop
|
||||
}
|
||||
|
||||
var coverBlocks []testing.CoverBlock
|
||||
var coverCounts []uint32
|
||||
|
||||
ipLoop:
|
||||
for _, ip := range hm[h] {
|
||||
for _, m := range c.DebugInfo.Methods {
|
||||
for _, sp := range m.SeqPoints {
|
||||
if sp.Opcode == ip {
|
||||
fmt.Println("FOUND COVER BLOCK")
|
||||
coverCounts = append(coverCounts, 1)
|
||||
coverBlocks = append(coverBlocks, testing.CoverBlock{
|
||||
Line0: uint32(sp.StartLine),
|
||||
Col0: uint16(sp.StartCol),
|
||||
Line1: uint32(sp.EndLine),
|
||||
Col1: uint16(sp.EndCol),
|
||||
Stmts: 1,
|
||||
})
|
||||
continue ipLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Blocks[name] = coverBlocks
|
||||
Counters[name] = coverCounts
|
||||
continue coverageLoop
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue