Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Iterator unit tests to use test runner #1019

Merged
merged 1 commit into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions boa3_test/test_drive/testrunner/neo_test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from boa3_test.test_drive.model.wallet.account import Account
from boa3_test.test_drive.neoxp import utils as neoxp_utils
from boa3_test.test_drive.neoxp.batch import NeoExpressBatch
from boa3_test.test_drive.testrunner import utils
from boa3_test.test_drive.testrunner.blockchain.block import TestRunnerBlock as Block
from boa3_test.test_drive.testrunner.blockchain.log import TestRunnerLog as Log
from boa3_test.test_drive.testrunner.blockchain.notification import TestRunnerNotification as Notification
Expand Down Expand Up @@ -272,6 +273,10 @@ def execute(self, account: Account = None, get_storage_from: Union[str, TestCont

try:
result = json.loads(stdout)
except json.JSONDecodeError:
result = utils.handle_return_error(stdout)

try:
self._update_runner(result)
if clear_invokes:
self._invokes.clear()
Expand Down
48 changes: 48 additions & 0 deletions boa3_test/test_drive/testrunner/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,51 @@ def value_to_parameter(value: Any) -> Any:

def bytes_to_hex(data: bytes) -> str:
return '0x' + data.hex()


def handle_return_error(json_result: str) -> dict:
import json

index = _get_first_json_closure(json_result)
result = json.loads(json_result[:index])
if 'stack' not in result:
return result

while index < len(json_result):
next_index = _get_first_json_closure(json_result, starting_index=index)
if next_index > index:
new_object = json.loads(json_result[index:next_index])
result['stack'].append(new_object)
else:
break
index = next_index

return result


def _get_first_json_closure(json_result: str, starting_index: int = 0):
if starting_index < 0:
starting_index = 0

open_object = []
open_array = []

if len(json_result) == starting_index or json_result[starting_index] != '{':
return starting_index

open_object.append(starting_index)
index = starting_index + 1
while index < len(json_result) and len(open_object):
char = json_result[index]
if char == '{':
open_object.append(index)
elif char == '}':
open_object.pop()
elif char == '[':
open_array.append(index)
elif char == ']':
open_array.pop()

index += 1

return index
9 changes: 7 additions & 2 deletions boa3_test/test_sc/interop_test/iterator/IteratorNext.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from boa3.builtin.compile_time import public
from boa3.builtin.interop.storage import find
from boa3.builtin.interop import storage


@public
def has_next(prefix: str) -> bool:
return find(prefix).next()
return storage.find(prefix).next()


@public
def store_data(key: str, value: int):
storage.put(key, value)
9 changes: 7 additions & 2 deletions boa3_test/test_sc/interop_test/iterator/IteratorValue.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from typing import Union

from boa3.builtin.compile_time import public
from boa3.builtin.interop.storage import find
from boa3.builtin.interop import storage


@public
def test_iterator(prefix: str) -> Union[tuple, None]:
it = find(prefix)
it = storage.find(prefix)
if it.next():
return it.value
return None


@public
def store_data(key: str, value: int):
storage.put(key, value)
142 changes: 99 additions & 43 deletions boa3_test/tests/compiler_tests/test_interop/test_iterator.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from boa3.internal.exception import CompilerError
from boa3.internal.neo3.vm import VMState
from boa3_test.test_drive.testrunner.neo_test_runner import NeoTestRunner
from boa3_test.tests.boa_test import BoaTest
from boa3_test.tests.test_classes.testengine import TestEngine


class TestIteratorInterop(BoaTest):
Expand All @@ -11,78 +12,133 @@ def test_iterator_create(self):
self.assertCompilerLogs(CompilerError.UnresolvedReference, path)

def test_iterator_next(self):
path = self.get_contract_path('IteratorNext.py')
engine = TestEngine()
path, _ = self.get_deploy_file_paths('IteratorNext.py')
runner = NeoTestRunner()

invokes = []
expected_results = []

prefix = 'test_iterator_next'
result = self.run_smart_contract(engine, path, 'has_next', prefix)
self.assertEqual(False, result)
invokes.append(runner.call_contract(path, 'has_next', prefix))
expected_results.append(False)

key = prefix + 'example1'
runner.call_contract(path, 'store_data', key, 1)
invokes.append(runner.call_contract(path, 'has_next', prefix))
expected_results.append(True)

engine.storage_put(prefix + 'example1', 1, contract_path=path)
result = self.run_smart_contract(engine, path, 'has_next', prefix)
self.assertEqual(True, result)
runner.execute()
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)

for x in range(len(invokes)):
self.assertEqual(expected_results[x], invokes[x].result)

def test_iterator_value(self):
path = self.get_contract_path('IteratorValue.py')
engine = TestEngine()
path, _ = self.get_deploy_file_paths('IteratorValue.py')
runner = NeoTestRunner()

invokes = []
expected_results = []

prefix = 'test_iterator_value'
result = self.run_smart_contract(engine, path, 'test_iterator', prefix)
self.assertIsNone(result)
invokes.append(runner.call_contract(path, 'test_iterator', prefix))
expected_results.append(None)

key = prefix + 'example1'
engine.storage_put(key, 1, contract_path=path)
result = self.run_smart_contract(engine, path, 'test_iterator', prefix)
self.assertEqual([key, '\x01'], result)
runner.call_contract(path, 'store_data', key, 1)
invokes.append(runner.call_contract(path, 'test_iterator', prefix))
expected_results.append([key, '\x01'])

runner.execute()
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)

for x in range(len(invokes)):
self.assertEqual(expected_results[x], invokes[x].result)

def test_iterator_value_dict_mismatched_type(self):
path = self.get_contract_path('IteratorValueMismatchedType.py')
self.assertCompilerLogs(CompilerError.MismatchedTypes, path)

def test_import_iterator(self):
path = self.get_contract_path('ImportIterator.py')
engine = TestEngine()
path, _ = self.get_deploy_file_paths('ImportIterator.py')
runner = NeoTestRunner()

invokes = []
expected_results = []

invokes.append(runner.call_contract(path, 'return_iterator'))
expected_results.append([])

runner.execute()
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)

result = self.run_smart_contract(engine, path, 'return_iterator')
self.assertEqual([], result)
for x in range(len(invokes)):
self.assertEqual(expected_results[x], invokes[x].result)

def test_import_interop_iterator(self):
path = self.get_contract_path('ImportInteropIterator.py')
engine = TestEngine()
path, _ = self.get_deploy_file_paths('ImportInteropIterator.py')
runner = NeoTestRunner()

result = self.run_smart_contract(engine, path, 'return_iterator')
self.assertEqual([], result)
invokes = []
expected_results = []

invokes.append(runner.call_contract(path, 'return_iterator'))
expected_results.append([])

runner.execute()
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)

for x in range(len(invokes)):
self.assertEqual(expected_results[x], invokes[x].result)

def test_iterator_implicit_typing(self):
path = self.get_contract_path('IteratorImplicitTyping.py')
engine = TestEngine()
path, _ = self.get_deploy_file_paths('IteratorImplicitTyping.py')
runner = NeoTestRunner()

invokes = []
expected_results = []

prefix = 'test_iterator_'
result = self.run_smart_contract(engine, path, 'search_storage', prefix)
self.assertEqual({}, result)
invokes.append(runner.call_contract(path, 'search_storage', prefix))
expected_results.append({})

invokes.append(runner.call_contract(path, 'store', f'{prefix}1', 1))
expected_results.append(None)

result = self.run_smart_contract(engine, path, 'store', f'{prefix}1', 1)
self.assertIsVoid(result)
invokes.append(runner.call_contract(path, 'store', f'{prefix}2', 2))
expected_results.append(None)

result = self.run_smart_contract(engine, path, 'store', f'{prefix}2', 2)
self.assertIsVoid(result)
invokes.append(runner.call_contract(path, 'search_storage', prefix))
expected_results.append({f'{prefix}1': 1, f'{prefix}2': 2})

result = self.run_smart_contract(engine, path, 'search_storage', prefix)
self.assertEqual({f'{prefix}1': 1, f'{prefix}2': 2}, result)
runner.execute()
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)

for x in range(len(invokes)):
self.assertEqual(expected_results[x], invokes[x].result)

def test_iterator_value_access(self):
path = self.get_contract_path('IteratorValueAccess.py')
engine = TestEngine()
path, _ = self.get_deploy_file_paths('IteratorValueAccess.py')
runner = NeoTestRunner()

invokes = []
expected_results = []

prefix = 'test_iterator_'
result = self.run_smart_contract(engine, path, 'search_storage', prefix)
self.assertEqual({}, result)
invokes.append(runner.call_contract(path, 'search_storage', prefix))
expected_results.append({})

invokes.append(runner.call_contract(path, 'store', f'{prefix}1', 1))
expected_results.append(None)

invokes.append(runner.call_contract(path, 'store', f'{prefix}2', 2))
expected_results.append(None)

result = self.run_smart_contract(engine, path, 'store', f'{prefix}1', 1)
self.assertIsVoid(result)
invokes.append(runner.call_contract(path, 'search_storage', prefix))
expected_results.append({f'{prefix}1': 1, f'{prefix}2': 2})

result = self.run_smart_contract(engine, path, 'store', f'{prefix}2', 2)
self.assertIsVoid(result)
runner.execute()
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)

result = self.run_smart_contract(engine, path, 'search_storage', prefix)
self.assertEqual({f'{prefix}1': 1, f'{prefix}2': 2}, result)
for x in range(len(invokes)):
self.assertEqual(expected_results[x], invokes[x].result)
Loading