2023-07-31 10:24:10 +00:00
|
|
|
package contract
|
2023-07-31 16:00:15 +00:00
|
|
|
|
|
|
|
import (
|
2023-08-07 08:10:58 +00:00
|
|
|
"errors"
|
|
|
|
"math/rand"
|
2023-07-31 16:00:15 +00:00
|
|
|
"path"
|
|
|
|
"testing"
|
|
|
|
|
2023-08-01 13:09:07 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/contract-coverage-primer/covertest"
|
2023-08-04 09:41:06 +00:00
|
|
|
"github.com/davecgh/go-spew/spew"
|
2023-08-07 08:10:58 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
2023-07-31 16:00:15 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
2023-08-04 09:41:06 +00:00
|
|
|
"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/vm"
|
2023-07-31 16:00:15 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
2023-08-04 09:41:06 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2023-07-31 16:00:15 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const ctrPath = "../impulse"
|
|
|
|
|
2023-08-07 08:56:12 +00:00
|
|
|
// keys for tests
|
2023-07-31 16:00:15 +00:00
|
|
|
var (
|
|
|
|
validKey = []byte{1, 2, 3, 4, 5}
|
|
|
|
invalidKey = []byte{1, 2, 3}
|
|
|
|
)
|
|
|
|
|
|
|
|
func newExecutor(t *testing.T) *neotest.Executor {
|
|
|
|
bc, acc := chain.NewSingle(t)
|
|
|
|
return neotest.NewExecutor(t, bc, acc, acc)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContract(t *testing.T) {
|
|
|
|
e := newExecutor(t)
|
2023-08-01 13:09:07 +00:00
|
|
|
ctrDI := covertest.CompileFile(t, e.CommitteeHash, ctrPath, path.Join(ctrPath, "config.yml"))
|
|
|
|
ctr := ctrDI.Contract
|
2023-07-31 16:00:15 +00:00
|
|
|
e.DeployContract(t, ctr, nil)
|
2023-08-08 14:14:07 +00:00
|
|
|
inv := covertest.CommitteeInvoker(e, ctr.Hash)
|
2023-07-31 16:00:15 +00:00
|
|
|
|
|
|
|
// test get without put
|
|
|
|
inv.InvokeFail(t, "Cannot get number", "getNumber", validKey)
|
|
|
|
|
|
|
|
// test put-get with valid key
|
|
|
|
inv.Invoke(t, stackitem.Null{}, "putNumber", validKey, 42)
|
|
|
|
inv.Invoke(t, 42, "getNumber", validKey)
|
|
|
|
|
|
|
|
// test invalid key
|
|
|
|
inv.InvokeFail(t, "Invalid key size", "putNumber", invalidKey, 42)
|
|
|
|
inv.InvokeFail(t, "Invalid key size", "getNumber", invalidKey)
|
2023-08-14 15:44:06 +00:00
|
|
|
// spew.Dump(inv.Methods)
|
|
|
|
inv.MakeCoverage(t, ctrDI, "contract.go", "c.out")
|
2023-07-31 16:00:15 +00:00
|
|
|
}
|
2023-08-04 09:41:06 +00:00
|
|
|
|
|
|
|
func TestRun(t *testing.T) {
|
|
|
|
e := newExecutor(t)
|
|
|
|
ctrDI := covertest.CompileFile(t, e.CommitteeHash, ctrPath, path.Join(ctrPath, "config.yml"))
|
|
|
|
e.DeployContract(t, ctrDI.Contract, nil)
|
|
|
|
|
2023-08-07 08:10:58 +00:00
|
|
|
startOffsetPutNumber, err := getStartOffset(ctrDI.DebugInfo, "PutNumber")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
hasResult, err := hasResult(ctrDI.DebugInfo, "PutNumber")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
someNum := getNumToPut()
|
|
|
|
|
2023-08-07 08:56:12 +00:00
|
|
|
// set up a VM for covertest.Run()
|
2023-08-07 08:10:58 +00:00
|
|
|
covertestRunVM := setUpVMForPut(t, e, ctrDI.Contract, hasResult, startOffsetPutNumber, someNum, invalidKey)
|
|
|
|
res, covErr := covertest.Run(covertestRunVM)
|
|
|
|
t.Log("Printing collected instructions:")
|
2023-08-04 09:41:06 +00:00
|
|
|
spew.Dump(res)
|
2023-08-07 08:10:58 +00:00
|
|
|
t.Log("covertest.Run() returned an error: ", covErr)
|
2023-08-04 09:41:06 +00:00
|
|
|
|
2023-08-07 08:56:12 +00:00
|
|
|
// set up a VM for vm.Run()
|
2023-08-07 08:10:58 +00:00
|
|
|
origRunVM := setUpVMForPut(t, e, ctrDI.Contract, hasResult, startOffsetPutNumber, someNum, invalidKey)
|
2023-08-04 09:41:06 +00:00
|
|
|
runerr := origRunVM.Run()
|
2023-08-07 08:10:58 +00:00
|
|
|
t.Log("vm.Run() returned an error: ", covErr)
|
2023-08-04 09:41:06 +00:00
|
|
|
|
2023-08-07 08:56:12 +00:00
|
|
|
// check if errors are the same
|
2023-08-07 08:10:58 +00:00
|
|
|
require.Equal(t, runerr.Error(), covErr.Error())
|
2023-08-04 09:41:06 +00:00
|
|
|
|
2023-08-07 08:56:12 +00:00
|
|
|
// check if the number of elements on the stack is the same
|
2023-08-07 08:10:58 +00:00
|
|
|
require.Equal(t, origRunVM.Estack().Len(), covertestRunVM.Estack().Len())
|
2023-08-04 09:41:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func setUpVMForPut(t *testing.T, e *neotest.Executor, contract *neotest.Contract, hasResult bool, methodOff int, num int, key []byte) (v *vm.VM) {
|
|
|
|
ic, err := e.Chain.GetTestVM(trigger.Application, nil, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
ic.VM.LoadNEFMethod(contract.NEF, contract.Hash, contract.Hash, callflag.All, hasResult, methodOff, -1, nil)
|
|
|
|
ic.VM.Context().Estack().PushVal(num)
|
|
|
|
ic.VM.Context().Estack().PushVal(key)
|
|
|
|
return ic.VM
|
|
|
|
}
|
2023-08-07 08:10:58 +00:00
|
|
|
|
|
|
|
func getStartOffset(di *compiler.DebugInfo, methodID string) (int, error) {
|
|
|
|
for _, method := range di.Methods {
|
|
|
|
if method.ID == methodID {
|
|
|
|
return int(method.Range.Start), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0, errors.New("Method not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
func hasResult(di *compiler.DebugInfo, methodID string) (bool, error) {
|
|
|
|
for _, method := range di.Methods {
|
|
|
|
if method.ID == methodID {
|
|
|
|
if method.ReturnType == "Void" {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, errors.New("Method not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
func getNumToPut() int {
|
|
|
|
return rand.Intn(100)
|
|
|
|
}
|