Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ dependencies = [
"pytest-mock>=3.10.0",
"pytest-xdist[psutil]>=3.3",
"py-algorand-sdk>=2.4.0",
"algokit-utils>=2.2.1",
"algokit-utils>=3.0.0b7",
"pytest-cov>=4.1.0",
"prettytable>=3.9.0",
"mypy==1.10",
Expand Down Expand Up @@ -171,7 +171,7 @@ dependencies = [
"pytest-mock>=3.10.0",
"pytest-xdist[psutil]>=3.3",
"py-algorand-sdk>=2.4.0",
"algokit-utils>=2.2.1",
"algokit-utils>=3.0.0b7",
"pytest-cov>=4.1.0",
"mypy==1.10",
]
Expand Down
12 changes: 6 additions & 6 deletions src/_algopy_testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
__all__ = [
"ARC4Contract",
"ARC4ValueGenerator",
"AVMValueGenerator",
"Account",
"AlgopyTestContext",
"Application",
Expand All @@ -39,20 +40,19 @@
"Bytes",
"Contract",
"GlobalState",
"ITxnGroupLoader",
"ITxnLoader",
"LedgerContext",
"LocalState",
"LogicSig",
"ITxnLoader",
"TxnValueGenerator",
"ITxnGroupLoader",
"OnCompleteAction",
"StateTotals",
"String",
"TemplateVar",
"LedgerContext",
"TransactionContext",
"AVMValueGenerator",
"TxnValueGenerator",
"TransactionType",
"TxnValueGenerator",
"TxnValueGenerator",
"UInt64",
"algopy_testing_context",
"arc4",
Expand Down
2 changes: 1 addition & 1 deletion src/_algopy_testing/models/txn_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,10 +508,10 @@ def wrapper(index: algopy.UInt64 | int) -> _T:
"AssetConfigFields",
"AssetFreezeFields",
"AssetTransferFields",
"TransactionFieldsGetter",
"KeyRegistrationFields",
"PaymentFields",
"TransactionFields",
"TransactionFieldsGetter",
"get_txn_defaults",
"narrow_field_type",
]
8 changes: 4 additions & 4 deletions src/algopy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@
from . import arc4, gtxn, itxn, op

__all__ = [
"ARC4Contract",
"Account",
"Application",
"ARC4Contract",
"Asset",
"BigUInt",
"Box",
"BoxMap",
"BoxRef",
"Bytes",
"BytesBacked",
"CompiledContract",
Expand Down Expand Up @@ -56,7 +59,4 @@
"subroutine",
"uenumerate",
"urange",
"Box",
"BoxRef",
"BoxMap",
]
6 changes: 3 additions & 3 deletions tests/arc4/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pathlib import Path

import pytest
from algosdk.v2client.algod import AlgodClient
from algokit_utils import AlgorandClient

from tests.common import AVMInvoker, create_avm_invoker

Expand All @@ -10,5 +10,5 @@


@pytest.fixture(scope="module")
def get_avm_result(algod_client: AlgodClient) -> AVMInvoker:
return create_avm_invoker(APP_SPEC, algod_client)
def get_avm_result(algorand: AlgorandClient) -> AVMInvoker:
return create_avm_invoker(APP_SPEC, algorand)
52 changes: 25 additions & 27 deletions tests/arc4/test_arc4_method_signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
import algopy
import algosdk
import pytest
from algokit_utils.beta.algorand_client import AlgorandClient, AssetCreateParams, PayParams
from algokit_utils import AlgoAmount, AlgorandClient, AssetCreateParams, PaymentParams
from algopy import arc4
from algosdk.atomic_transaction_composer import TransactionWithSigner
from algosdk.v2client.algod import AlgodClient

from tests.artifacts.Arc4ABIMethod.contract import (
AnotherStruct,
Expand All @@ -25,8 +24,8 @@


@pytest.fixture()
def get_avm_result(algod_client: AlgodClient) -> AVMInvoker:
return create_avm_invoker(APP_SPEC, algod_client)
def get_avm_result(algorand: AlgorandClient) -> AVMInvoker:
return create_avm_invoker(APP_SPEC, algorand)


@pytest.fixture()
Expand All @@ -36,25 +35,22 @@ def context() -> Generator[_algopy_testing.AlgopyTestContext, None, None]:


@pytest.fixture()
def funded_account(algod_client: AlgodClient, context: _algopy_testing.AlgopyTestContext) -> str:
pk, address = algosdk.account.generate_account()
assert isinstance(address, str)
algokit_utils.ensure_funded(
algod_client,
algokit_utils.EnsureBalanceParameters(
account_to_fund=address,
min_spending_balance_micro_algos=_FUNDED_ACCOUNT_SPENDING,
),
def funded_account(algorand: AlgorandClient, context: _algopy_testing.AlgopyTestContext) -> str:
account = algorand.account.random()
algorand.account.ensure_funded_from_environment(
account_to_fund=account,
min_spending_balance=algokit_utils.AlgoAmount(micro_algo=_FUNDED_ACCOUNT_SPENDING),
)

# ensure context has the same account with matching balance
context.any.account(address, balance=algopy.Global.min_balance + _FUNDED_ACCOUNT_SPENDING)
return address
context.any.account(
account.address, balance=algopy.Global.min_balance + _FUNDED_ACCOUNT_SPENDING
)
return account.address


@pytest.fixture()
def other_app_id(algod_client: AlgodClient, context: _algopy_testing.AlgopyTestContext) -> int:
second_invoker = create_avm_invoker(APP_SPEC, algod_client)
def other_app_id(algorand: AlgorandClient, context: _algopy_testing.AlgopyTestContext) -> int:
second_invoker = create_avm_invoker(APP_SPEC, algorand)
client = second_invoker.client
app_id = client.app_id

Expand Down Expand Up @@ -127,14 +123,14 @@ def test_app_args_is_correct_with_txn(
"with_txn",
value="hello",
pay=TransactionWithSigner(
txn=algorand.transactions.payment(
PayParams(
txn=algorand.create_transaction.payment(
PaymentParams(
sender=localnet_creator_address,
receiver=localnet_creator_address,
amount=123,
amount=AlgoAmount(micro_algo=123),
)
),
signer=algorand.account.get_signer("default"),
signer=algorand.account.get_signer(localnet_creator_address),
),
arr=[1, 2],
)
Expand Down Expand Up @@ -169,7 +165,9 @@ def test_app_args_is_correct_with_asset(
sender=localnet_creator_address,
total=123,
)
)["confirmation"]["asset-index"]
).confirmation[
"asset-index"
] # type: ignore[call-overload]

# act
get_avm_result("with_asset", value="hello", asset=asa_id, arr=[1, 2])
Expand Down Expand Up @@ -333,14 +331,14 @@ def test_prepare_txns_with_complex(
"complex_sig",
struct1=((1, "2"), (1, "2"), 3, 4),
txn=TransactionWithSigner(
txn=algorand.transactions.payment(
PayParams(
txn=algorand.create_transaction.payment(
PaymentParams(
sender=localnet_creator_address,
receiver=localnet_creator_address,
amount=123,
amount=AlgoAmount(micro_algo=123),
)
),
signer=algorand.account.get_signer("default"),
signer=algorand.account.get_signer(localnet_creator_address),
),
acc=funded_account,
five=[5],
Expand Down
99 changes: 46 additions & 53 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@

import algosdk
from algokit_utils import (
Account,
ApplicationClient,
EnsureBalanceParameters,
ensure_funded,
get_localnet_default_account,
AlgorandClient,
AppClient,
AppClientMethodCallParams,
AppFactory,
AppFactoryCreateMethodCallParams,
AppFactoryCreateParams,
AppFactoryParams,
SigningAccount,
)
from algosdk.v2client.algod import AlgodClient

Expand All @@ -21,65 +24,70 @@ class AVMInvoker:
"""Protocol used in global test fixtures to simplify invocation of AVM methods via an Algokit
typed client."""

def __init__(self, client: ApplicationClient):
def __init__(self, client: AppClient, factory: AppFactory):
self.client = client
self.factory = factory

def __call__(
self,
method: str,
on_complete: algosdk.transaction.OnComplete = algosdk.transaction.OnComplete.NoOpOC,
**kwargs: typing.Any,
) -> object:
response = self.client.call(
method,
transaction_parameters={
# random note avoids duplicate txn if tests are running concurrently
"note": _random_note(),
"accounts": kwargs.pop("accounts", None),
"foreign_apps": kwargs.pop("foreign_apps", None),
"foreign_assets": kwargs.pop("foreign_assets", None),
"suggested_params": kwargs.pop("suggested_params", None),
"on_complete": on_complete,
},
**kwargs,
response = self.client.send.call(
AppClientMethodCallParams(
method=method,
note=_random_note(),
account_references=kwargs.pop("accounts", None),
app_references=kwargs.pop("foreign_apps", None),
asset_references=kwargs.pop("foreign_assets", None),
on_complete=on_complete,
args=[item[1] for item in kwargs.items()],
static_fee=kwargs.pop("static_fee", None),
),
)
if response.decode_error:
raise ValueError(response.decode_error)
result = response.return_value
if result is None:
return response.tx_info.get("logs", None)
if response.returns and len(response.returns) > 0 and response.returns[0].decode_error:
raise ValueError(response.returns[0].decode_error)
result = response.abi_return
if result is None and response.returns and len(response.returns) > 0:
assert response.returns[0].tx_info
return response.returns[0].tx_info.get("logs", None)
if isinstance(result, list) and all(
isinstance(i, int) and i >= 0 and i <= 255 for i in result
):
return bytes(result)
return bytes(result) # type: ignore[arg-type]
return result


def _random_note() -> bytes:
return secrets.token_bytes(8)


def create_avm_invoker(app_spec: Path, algod_client: AlgodClient) -> AVMInvoker:
client = ApplicationClient(
algod_client,
app_spec,
signer=get_localnet_default_account(algod_client),
)

client.create(
transaction_parameters={
# random note avoids duplicate txn if tests are running concurrently
"note": _random_note(),
}
def create_avm_invoker(app_spec: Path, algorand: AlgorandClient) -> AVMInvoker:
dispenser = algorand.account.localnet_dispenser()
factory = AppFactory(
AppFactoryParams(
algorand=algorand,
app_spec=app_spec.read_text(),
default_sender=dispenser.address,
),
)
try:
client, _ = factory.send.bare.create(
AppFactoryCreateParams(note=_random_note()),
)
except Exception as __:
client, _ = factory.send.create(
AppFactoryCreateMethodCallParams(method="create", note=_random_note()),
)

return AVMInvoker(client)
return AVMInvoker(client, factory)


def generate_test_asset( # noqa: PLR0913
*,
algod_client: AlgodClient,
sender: Account,
sender: SigningAccount,
total: int | None = None,
decimals: int = 0,
default_frozen: bool = False,
Expand Down Expand Up @@ -134,18 +142,3 @@ def generate_test_asset( # noqa: PLR0913
return ptx["asset-index"]
else:
raise ValueError("Unexpected response from pending_transaction_info")


def generate_test_account(algod_client: AlgodClient) -> Account:
raw_account = algosdk.account.generate_account()
account = Account(private_key=raw_account[0], address=raw_account[1])

ensure_funded(
algod_client,
EnsureBalanceParameters(
account_to_fund=account,
min_spending_balance_micro_algos=INITIAL_BALANCE_MICRO_ALGOS,
),
)

return account
Loading