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
|
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 {
|
func (e *Executor) GenerateNewBlocks(t testing.TB, count int) []*block.Block {
|
||||||
blocks := make([]*block.Block, count)
|
blocks := make([]*block.Block, count)
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package neotest
|
package neotest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"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.
|
// 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) {
|
func (c *ContractInvoker) TestInvoke(t testing.TB, method string, args ...interface{}) (*vm.Stack, error) {
|
||||||
|
fmt.Println("TEST INVOKE")
|
||||||
tx := c.PrepareInvokeNoSign(t, method, args...)
|
tx := c.PrepareInvokeNoSign(t, method, args...)
|
||||||
b := c.NewUnsignedBlock(t, tx)
|
b := c.NewUnsignedBlock(t, tx)
|
||||||
|
|
||||||
|
calculateCoverage(t, c.Chain, tx, b)
|
||||||
|
|
||||||
ic := c.Chain.GetTestVM(trigger.Application, tx, b)
|
ic := c.Chain.GetTestVM(trigger.Application, tx, b)
|
||||||
t.Cleanup(ic.Finalize)
|
t.Cleanup(ic.Finalize)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package neotest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
||||||
|
@ -16,9 +17,10 @@ import (
|
||||||
|
|
||||||
// Contract contains contract info for deployment.
|
// Contract contains contract info for deployment.
|
||||||
type Contract struct {
|
type Contract struct {
|
||||||
Hash util.Uint160
|
Hash util.Uint160
|
||||||
NEF *nef.File
|
NEF *nef.File
|
||||||
Manifest *manifest.Manifest
|
Manifest *manifest.Manifest
|
||||||
|
DebugInfo *compiler.DebugInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// contracts caches the compiled contracts from FS across multiple tests.
|
// 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.
|
// 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 {
|
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 {
|
if c, ok := contracts[srcPath]; ok {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -72,9 +79,10 @@ func CompileFile(t testing.TB, sender util.Uint160, srcPath string, configPath s
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
c := &Contract{
|
c := &Contract{
|
||||||
Hash: state.CreateContractHash(sender, ne.Checksum, m.Name),
|
Hash: state.CreateContractHash(sender, ne.Checksum, m.Name),
|
||||||
NEF: ne,
|
NEF: ne,
|
||||||
Manifest: m,
|
Manifest: m,
|
||||||
|
DebugInfo: di,
|
||||||
}
|
}
|
||||||
contracts[srcPath] = c
|
contracts[srcPath] = c
|
||||||
return 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