From 50d515a3e5012398c1771ddaeff351bacbbf7200 Mon Sep 17 00:00:00 2001
From: Evgeniy Stratonikov <evgeniy@nspcc.ru>
Date: Tue, 12 Jan 2021 15:52:08 +0300
Subject: [PATCH] cli: add tests for Storage.Find invocations

It returns values of different types we better be sure that
compiler emits correct code.
---
 cli/contract_test.go        | 38 +++++++++++++++++++++++++++++++++++++
 cli/testdata/deploy/main.go | 15 +++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/cli/contract_test.go b/cli/contract_test.go
index 4db8aca80..f8886d33c 100644
--- a/cli/contract_test.go
+++ b/cli/contract_test.go
@@ -6,11 +6,13 @@ import (
 	"io/ioutil"
 	"os"
 	"path"
+	"strconv"
 	"strings"
 	"testing"
 
 	"github.com/nspcc-dev/neo-go/internal/random"
 	"github.com/nspcc-dev/neo-go/pkg/config"
+	"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
 	"github.com/nspcc-dev/neo-go/pkg/core/state"
 	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
 	"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
@@ -18,6 +20,7 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
 	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neo-go/pkg/vm"
+	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
 	"github.com/stretchr/testify/require"
 )
 
@@ -254,6 +257,41 @@ func TestComlileAndInvokeFunction(t *testing.T) {
 		})
 	})
 
+	t.Run("test Storage.Find", func(t *testing.T) {
+		cmd := []string{"neo-go", "contract", "testinvokefunction",
+			"--rpc-endpoint", "http://" + e.RPC.Addr,
+			h.StringLE(), "testFind"}
+
+		t.Run("keys only", func(t *testing.T) {
+			e.Run(t, append(cmd, strconv.FormatInt(storage.FindKeysOnly, 10))...)
+			res := new(result.Invoke)
+			require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
+			require.Equal(t, vm.HaltState.String(), res.State)
+			require.Len(t, res.Stack, 1)
+			require.Equal(t, []stackitem.Item{
+				stackitem.Make("findkey1"),
+				stackitem.Make("findkey2"),
+			}, res.Stack[0].Value())
+		})
+		t.Run("both", func(t *testing.T) {
+			e.Run(t, append(cmd, strconv.FormatInt(storage.FindDefault, 10))...)
+			res := new(result.Invoke)
+			require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
+			require.Equal(t, vm.HaltState.String(), res.State)
+			require.Len(t, res.Stack, 1)
+
+			arr, ok := res.Stack[0].Value().([]stackitem.Item)
+			require.True(t, ok)
+			require.Len(t, arr, 2)
+			require.Equal(t, []stackitem.Item{
+				stackitem.Make("findkey1"), stackitem.Make("value1"),
+			}, arr[0].Value())
+			require.Equal(t, []stackitem.Item{
+				stackitem.Make("findkey2"), stackitem.Make("value2"),
+			}, arr[1].Value())
+		})
+	})
+
 	t.Run("Update", func(t *testing.T) {
 		nefName := path.Join(tmpDir, "updated.nef")
 		manifestName := path.Join(tmpDir, "updated.manifest.json")
diff --git a/cli/testdata/deploy/main.go b/cli/testdata/deploy/main.go
index dcadc30ea..514c3e448 100644
--- a/cli/testdata/deploy/main.go
+++ b/cli/testdata/deploy/main.go
@@ -4,6 +4,7 @@ import (
 	"github.com/nspcc-dev/neo-go/cli/testdata/deploy/sub"
 	"github.com/nspcc-dev/neo-go/pkg/interop"
 	"github.com/nspcc-dev/neo-go/pkg/interop/contract"
+	"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
 	"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
 	"github.com/nspcc-dev/neo-go/pkg/interop/storage"
 )
@@ -46,3 +47,17 @@ func GetValue() string {
 	val2 := storage.Get(ctx, sub.Key)
 	return val1.(string) + "|" + val2.(string)
 }
+
+// TestFind finds items with the specified prefix.
+func TestFind(f storage.FindFlags) []interface{} {
+	ctx := storage.GetContext()
+	storage.Put(ctx, "findkey1", "value1")
+	storage.Put(ctx, "findkey2", "value2")
+
+	var result []interface{}
+	iter := storage.Find(ctx, "findkey", f)
+	for iterator.Next(iter) {
+		result = append(result, iterator.Value(iter))
+	}
+	return result
+}