diff --git a/examples/auction/test_contract.py b/examples/auction/test_contract.py index 2aae01b..8187411 100644 --- a/examples/auction/test_contract.py +++ b/examples/auction/test_contract.py @@ -1,165 +1,164 @@ -# import time -# from collections.abc import Generator - -# import algopy -# import pytest -# from algopy_testing import AlgopyTestContext, algopy_testing_context - -# from .contract import AuctionContract - - -# @pytest.fixture() -# def context() -> Generator[AlgopyTestContext, None, None]: -# with algopy_testing_context() as ctx: -# yield ctx -# ctx.reset() - - -# def test_opt_into_asset(context: AlgopyTestContext) -> None: -# # Arrange -# asset = context.any.asset() -# contract = AuctionContract() - -# # Act -# contract.opt_into_asset(asset) - -# # Assert -# assert contract.asa.id == asset.id -# inner_txn = context.txn.last_group.last_itxn.asset_transfer -# assert ( -# inner_txn.asset_receiver == context.get_app_for_contract(contract).address -# ), "Asset receiver does not match" -# assert inner_txn.xfer_asset == asset, "Transferred asset does not match" - - -# def test_start_auction( -# context: AlgopyTestContext, -# ) -> None: -# # Arrange -# contract = AuctionContract() -# app = context.get_app_for_contract(contract) -# latest_timestamp = context.any.uint64(1, 1000) -# starting_price = context.any.uint64() -# auction_duration = context.any.uint64(100, 1000) -# axfer_txn = context.any.txn.asset_transfer( -# asset_receiver=app.address, -# asset_amount=starting_price, -# ) -# contract.asa_amount = starting_price -# context.ledger.patch_global_fields( -# latest_timestamp=latest_timestamp, -# ) - -# # Act -# with context.txn.create_group(txn_op_fields={"sender": context.default_sender}): -# contract.start_auction( -# starting_price, -# auction_duration, -# axfer_txn, -# ) - -# # Assert -# assert contract.auction_end == latest_timestamp + auction_duration -# assert contract.previous_bid == starting_price -# assert contract.asa_amount == starting_price - - -# def test_bid(context: AlgopyTestContext) -> None: -# # Arrange -# account = context.default_sender -# auction_end = context.any.uint64(min_value=int(time.time()) + 10_000) -# previous_bid = context.any.uint64(1, 100) -# pay_amount = context.any.uint64() - -# contract = AuctionContract() -# contract.auction_end = auction_end -# contract.previous_bid = previous_bid -# pay = context.any.txn.payment(sender=account, amount=pay_amount) - -# # Act -# contract.bid(pay=pay) - -# # Assert -# assert contract.previous_bid == pay_amount -# assert contract.previous_bidder == account -# assert contract.claimable_amount[account] == pay_amount - - -# def test_claim_bids( -# context: AlgopyTestContext, -# ) -> None: -# # Arrange -# account = context.any.account() -# contract = AuctionContract() -# claimable_amount = context.any.uint64() -# contract.claimable_amount[account] = claimable_amount -# contract.previous_bidder = account -# previous_bid = context.any.uint64(max_value=int(claimable_amount)) -# contract.previous_bid = previous_bid - -# # Act -# with context.txn.create_group(txn_op_fields={"sender": account}): -# contract.claim_bids() - -# # Assert -# expected_payment = claimable_amount - previous_bid -# last_inner_txn = context.txn.last_group.last_itxn.payment - -# assert last_inner_txn.amount == expected_payment -# assert last_inner_txn.receiver == account -# assert contract.claimable_amount[account] == claimable_amount - expected_payment - - -# def test_claim_asset(context: AlgopyTestContext) -> None: -# # Arrange -# context.ledger.patch_global_fields(latest_timestamp=context.any.uint64()) -# contract = AuctionContract() -# contract.auction_end = context.any.uint64(1, 100) -# contract.previous_bidder = context.default_sender -# asa_amount = context.any.uint64(1000, 2000) -# contract.asa_amount = asa_amount -# asset = context.any.asset() - -# # Act -# contract.claim_asset(asset) - -# # Assert -# last_inner_txn = context.txn.last_group.last_itxn.asset_transfer -# assert last_inner_txn.xfer_asset == asset -# assert last_inner_txn.asset_close_to == context.default_sender -# assert last_inner_txn.asset_receiver == context.default_sender -# assert last_inner_txn.asset_amount == asa_amount - - -# def test_delete_application( -# context: AlgopyTestContext, -# ) -> None: -# # Arrange -# account = context.any.account() - -# # Act -# # setting sender will determine creator -# with context.txn.create_group(txn_op_fields={"sender": account}): -# contract = AuctionContract() - -# with context.txn.create_group( -# gtxns=[ -# context.any.txn.application_call( -# on_completion=algopy.OnCompleteAction.DeleteApplication -# ) -# ] -# ): -# contract.delete_application() - -# # Assert -# inner_transactions = context.txn.last_group.last_itxn.payment -# assert inner_transactions -# assert inner_transactions.type == algopy.TransactionType.Payment -# assert inner_transactions.receiver == account -# assert inner_transactions.close_remainder_to == account - - -# @pytest.mark.usefixtures("context") -# def test_clear_state_program() -> None: -# contract = AuctionContract() -# assert contract.clear_state_program() +import time +from collections.abc import Generator + +import algopy +import pytest +from algopy_testing import AlgopyTestContext, algopy_testing_context + +from .contract import AuctionContract + + +@pytest.fixture() +def context() -> Generator[AlgopyTestContext, None, None]: + with algopy_testing_context() as ctx: + yield ctx + + +def test_opt_into_asset(context: AlgopyTestContext) -> None: + # Arrange + asset = context.any.asset() + contract = AuctionContract() + + # Act + contract.opt_into_asset(asset) + + # Assert + assert contract.asa.id == asset.id + inner_txn = context.txn.last_group.last_itxn.asset_transfer + assert ( + inner_txn.asset_receiver == context.get_app_for_contract(contract).address + ), "Asset receiver does not match" + assert inner_txn.xfer_asset == asset, "Transferred asset does not match" + + +def test_start_auction( + context: AlgopyTestContext, +) -> None: + # Arrange + contract = AuctionContract() + app = context.get_app_for_contract(contract) + latest_timestamp = context.any.uint64(1, 1000) + starting_price = context.any.uint64() + auction_duration = context.any.uint64(100, 1000) + axfer_txn = context.any.txn.asset_transfer( + asset_receiver=app.address, + asset_amount=starting_price, + ) + contract.asa_amount = starting_price + context.ledger.patch_global_fields( + latest_timestamp=latest_timestamp, + ) + + # Act + with context.txn.create_group(txn_op_fields={"sender": context.default_sender}): + contract.start_auction( + starting_price, + auction_duration, + axfer_txn, + ) + + # Assert + assert contract.auction_end == latest_timestamp + auction_duration + assert contract.previous_bid == starting_price + assert contract.asa_amount == starting_price + + +def test_bid(context: AlgopyTestContext) -> None: + # Arrange + account = context.default_sender + auction_end = context.any.uint64(min_value=int(time.time()) + 10_000) + previous_bid = context.any.uint64(1, 100) + pay_amount = context.any.uint64() + + contract = AuctionContract() + contract.auction_end = auction_end + contract.previous_bid = previous_bid + pay = context.any.txn.payment(sender=account, amount=pay_amount) + + # Act + contract.bid(pay=pay) + + # Assert + assert contract.previous_bid == pay_amount + assert contract.previous_bidder == account + assert contract.claimable_amount[account] == pay_amount + + +def test_claim_bids( + context: AlgopyTestContext, +) -> None: + # Arrange + account = context.any.account() + contract = AuctionContract() + claimable_amount = context.any.uint64() + contract.claimable_amount[account] = claimable_amount + contract.previous_bidder = account + previous_bid = context.any.uint64(max_value=int(claimable_amount)) + contract.previous_bid = previous_bid + + # Act + with context.txn.create_group(txn_op_fields={"sender": account}): + contract.claim_bids() + + # Assert + expected_payment = claimable_amount - previous_bid + last_inner_txn = context.txn.last_group.last_itxn.payment + + assert last_inner_txn.amount == expected_payment + assert last_inner_txn.receiver == account + assert contract.claimable_amount[account] == claimable_amount - expected_payment + + +def test_claim_asset(context: AlgopyTestContext) -> None: + # Arrange + context.ledger.patch_global_fields(latest_timestamp=context.any.uint64()) + contract = AuctionContract() + contract.auction_end = context.any.uint64(1, 100) + contract.previous_bidder = context.default_sender + asa_amount = context.any.uint64(1000, 2000) + contract.asa_amount = asa_amount + asset = context.any.asset() + + # Act + contract.claim_asset(asset) + + # Assert + last_inner_txn = context.txn.last_group.last_itxn.asset_transfer + assert last_inner_txn.xfer_asset == asset + assert last_inner_txn.asset_close_to == context.default_sender + assert last_inner_txn.asset_receiver == context.default_sender + assert last_inner_txn.asset_amount == asa_amount + + +def test_delete_application( + context: AlgopyTestContext, +) -> None: + # Arrange + account = context.any.account() + + # Act + # setting sender will determine creator + with context.txn.create_group(txn_op_fields={"sender": account}): + contract = AuctionContract() + + with context.txn.create_group( + gtxns=[ + context.any.txn.application_call( + on_completion=algopy.OnCompleteAction.DeleteApplication + ) + ] + ): + contract.delete_application() + + # Assert + inner_transactions = context.txn.last_group.last_itxn.payment + assert inner_transactions + assert inner_transactions.type == algopy.TransactionType.Payment + assert inner_transactions.receiver == context.default_sender + assert inner_transactions.close_remainder_to == context.default_sender + + +@pytest.mark.usefixtures("context") +def test_clear_state_program() -> None: + contract = AuctionContract() + assert contract.clear_state_program() diff --git a/examples/box/test_contract.py b/examples/box/test_contract.py deleted file mode 100644 index 9ef04b8..0000000 --- a/examples/box/test_contract.py +++ /dev/null @@ -1,26 +0,0 @@ -from collections.abc import Generator - -import pytest -from algopy import op -from algopy_testing import AlgopyTestContext, algopy_testing_context - -from .contract import BoxContract - - -@pytest.fixture() -def context() -> Generator[AlgopyTestContext, None, None]: - with algopy_testing_context() as ctx: - yield ctx - - -def test_enums(context: AlgopyTestContext) -> None: - # Arrange - contract = BoxContract() - - # Act - contract.store_enums() - oca, txn = contract.read_enums() - - # Assert - assert context.ledger.get_box(contract, b"oca") == op.itob(oca.native) - assert context.ledger.get_box(contract, b"txn") == op.itob(txn.native) diff --git a/examples/htlc_logicsig/test_signature.py b/examples/htlc_logicsig/test_signature.py index b5cd2cc..0317a6d 100644 --- a/examples/htlc_logicsig/test_signature.py +++ b/examples/htlc_logicsig/test_signature.py @@ -12,7 +12,6 @@ def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() def test_seller_receives_payment(context: AlgopyTestContext) -> None: diff --git a/examples/marketplace/test_contract.py b/examples/marketplace/test_contract.py index 122bf51..30cb34e 100644 --- a/examples/marketplace/test_contract.py +++ b/examples/marketplace/test_contract.py @@ -17,7 +17,6 @@ def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() @pytest.fixture() diff --git a/examples/proof_of_attendance/test_contract.py b/examples/proof_of_attendance/test_contract.py index 535bc4c..c3a4e6f 100644 --- a/examples/proof_of_attendance/test_contract.py +++ b/examples/proof_of_attendance/test_contract.py @@ -12,7 +12,6 @@ def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() @pytest.fixture() diff --git a/examples/scratch_storage/test_contract.py b/examples/scratch_storage/test_contract.py index f3475c2..094a043 100644 --- a/examples/scratch_storage/test_contract.py +++ b/examples/scratch_storage/test_contract.py @@ -10,7 +10,6 @@ def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() def test_arc4_contract(context: AlgopyTestContext) -> None: diff --git a/examples/simple_voting/test_contract.py b/examples/simple_voting/test_contract.py index bbebe2f..4d8a6c3 100644 --- a/examples/simple_voting/test_contract.py +++ b/examples/simple_voting/test_contract.py @@ -11,7 +11,6 @@ def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() @pytest.mark.usefixtures("context") diff --git a/examples/zk_whitelist/test_contract.py b/examples/zk_whitelist/test_contract.py index 9c4255e..5319fff 100644 --- a/examples/zk_whitelist/test_contract.py +++ b/examples/zk_whitelist/test_contract.py @@ -13,7 +13,6 @@ def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() @pytest.fixture() diff --git a/tests/arc4/test_abi_call.py b/tests/arc4/test_abi_call.py index 5b4f8ad..2ba1e0e 100644 --- a/tests/arc4/test_abi_call.py +++ b/tests/arc4/test_abi_call.py @@ -18,7 +18,6 @@ def echo(self, value: arc4.String) -> arc4.String: def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() def test_mocking_required_for_abi_call(context: AlgopyTestContext) -> None: diff --git a/tests/arc4/test_arc4_method_signature.py b/tests/arc4/test_arc4_method_signature.py index 3f3a9d5..c7b522b 100644 --- a/tests/arc4/test_arc4_method_signature.py +++ b/tests/arc4/test_arc4_method_signature.py @@ -33,7 +33,6 @@ def get_avm_result(algod_client: AlgodClient) -> AVMInvoker: def context() -> Generator[algopy_testing.AlgopyTestContext, None, None]: with algopy_testing.algopy_testing_context() as ctx: yield ctx - ctx.reset() @pytest.fixture() diff --git a/tests/arc4/test_emit.py b/tests/arc4/test_emit.py index 0c7df77..e112198 100644 --- a/tests/arc4/test_emit.py +++ b/tests/arc4/test_emit.py @@ -56,7 +56,6 @@ class SwappedArc4(arc4.Struct): def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() def test_emit(get_avm_result: AVMInvoker, context: AlgopyTestContext) -> None: diff --git a/examples/box/__init__.py b/tests/artifacts/BoxContract/__init__.py similarity index 100% rename from examples/box/__init__.py rename to tests/artifacts/BoxContract/__init__.py diff --git a/examples/box/contract.py b/tests/artifacts/BoxContract/contract.py similarity index 100% rename from examples/box/contract.py rename to tests/artifacts/BoxContract/contract.py diff --git a/tests/artifacts/BoxContract/data/BoxContract.approval.teal b/tests/artifacts/BoxContract/data/BoxContract.approval.teal new file mode 100644 index 0000000..ad0f79d --- /dev/null +++ b/tests/artifacts/BoxContract/data/BoxContract.approval.teal @@ -0,0 +1,151 @@ +#pragma version 10 + +tests.artifacts.BoxContract.contract.BoxContract.approval_program: + // tests/artifacts/BoxContract/contract.py:4 + // class BoxContract(ARC4Contract): + txn NumAppArgs + bz main_bare_routing@6 + method "store_enums()void" + method "read_enums()(uint64,uint64)" + txna ApplicationArgs 0 + match main_store_enums_route@2 main_read_enums_route@3 + err // reject transaction + +main_store_enums_route@2: + // tests/artifacts/BoxContract/contract.py:9 + // @arc4.abimethod() + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + callsub store_enums + int 1 + return + +main_read_enums_route@3: + // tests/artifacts/BoxContract/contract.py:14 + // @arc4.abimethod() + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + callsub read_enums + byte 0x151f7c75 + swap + concat + log + int 1 + return + +main_bare_routing@6: + // tests/artifacts/BoxContract/contract.py:4 + // class BoxContract(ARC4Contract): + txn OnCompletion + ! + assert // reject transaction + txn ApplicationID + ! + assert // is creating + int 1 + return + + +// tests.artifacts.BoxContract.contract.BoxContract.store_enums() -> void: +store_enums: + // tests/artifacts/BoxContract/contract.py:9-10 + // @arc4.abimethod() + // def store_enums(self) -> None: + proto 0 0 + // tests/artifacts/BoxContract/contract.py:11 + // self.oca.value = OnCompleteAction.OptIn + int OptIn + itob + // tests/artifacts/BoxContract/contract.py:6 + // self.oca = Box(OnCompleteAction) + byte "oca" + // tests/artifacts/BoxContract/contract.py:11 + // self.oca.value = OnCompleteAction.OptIn + swap + box_put + // tests/artifacts/BoxContract/contract.py:12 + // self.txn.value = TransactionType.ApplicationCall + int appl + itob + // tests/artifacts/BoxContract/contract.py:7 + // self.txn = Box(TransactionType) + byte "txn" + // tests/artifacts/BoxContract/contract.py:12 + // self.txn.value = TransactionType.ApplicationCall + swap + box_put + retsub + + +// tests.artifacts.BoxContract.contract.BoxContract.read_enums() -> bytes: +read_enums: + // tests/artifacts/BoxContract/contract.py:14-15 + // @arc4.abimethod() + // def read_enums(self) -> arc4.Tuple[arc4.UInt64, arc4.UInt64]: + proto 0 1 + // tests/artifacts/BoxContract/contract.py:16 + // assert op.Box.get(b"oca")[0] == op.itob(self.oca.value) + byte 0x6f6361 + box_get + pop + // tests/artifacts/BoxContract/contract.py:6 + // self.oca = Box(OnCompleteAction) + byte "oca" + // tests/artifacts/BoxContract/contract.py:16 + // assert op.Box.get(b"oca")[0] == op.itob(self.oca.value) + box_get + swap + btoi + swap + assert // check self.oca exists + itob + == + assert + // tests/artifacts/BoxContract/contract.py:17 + // assert op.Box.get(b"txn")[0] == op.itob(self.txn.value) + byte 0x74786e + box_get + pop + // tests/artifacts/BoxContract/contract.py:7 + // self.txn = Box(TransactionType) + byte "txn" + // tests/artifacts/BoxContract/contract.py:17 + // assert op.Box.get(b"txn")[0] == op.itob(self.txn.value) + box_get + swap + btoi + swap + assert // check self.txn exists + itob + == + assert + // tests/artifacts/BoxContract/contract.py:6 + // self.oca = Box(OnCompleteAction) + byte "oca" + // tests/artifacts/BoxContract/contract.py:19 + // return arc4.Tuple((arc4.UInt64(self.oca.value), arc4.UInt64(self.txn.value))) + box_get + swap + btoi + swap + assert // check self.oca exists + itob + // tests/artifacts/BoxContract/contract.py:7 + // self.txn = Box(TransactionType) + byte "txn" + // tests/artifacts/BoxContract/contract.py:19 + // return arc4.Tuple((arc4.UInt64(self.oca.value), arc4.UInt64(self.txn.value))) + box_get + swap + btoi + swap + assert // check self.txn exists + itob + concat + retsub diff --git a/tests/artifacts/BoxContract/data/BoxContract.arc32.json b/tests/artifacts/BoxContract/data/BoxContract.arc32.json new file mode 100644 index 0000000..4e43a17 --- /dev/null +++ b/tests/artifacts/BoxContract/data/BoxContract.arc32.json @@ -0,0 +1,63 @@ +{ + "hints": { + "store_enums()void": { + "call_config": { + "no_op": "CALL" + } + }, + "read_enums()(uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgp0ZXN0cy5hcnRpZmFjdHMuQm94Q29udHJhY3QuY29udHJhY3QuQm94Q29udHJhY3QuYXBwcm92YWxfcHJvZ3JhbToKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weTo0CiAgICAvLyBjbGFzcyBCb3hDb250cmFjdChBUkM0Q29udHJhY3QpOgogICAgdHhuIE51bUFwcEFyZ3MKICAgIGJ6IG1haW5fYmFyZV9yb3V0aW5nQDYKICAgIG1ldGhvZCAic3RvcmVfZW51bXMoKXZvaWQiCiAgICBtZXRob2QgInJlYWRfZW51bXMoKSh1aW50NjQsdWludDY0KSIKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDAKICAgIG1hdGNoIG1haW5fc3RvcmVfZW51bXNfcm91dGVAMiBtYWluX3JlYWRfZW51bXNfcm91dGVAMwogICAgZXJyIC8vIHJlamVjdCB0cmFuc2FjdGlvbgoKbWFpbl9zdG9yZV9lbnVtc19yb3V0ZUAyOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIHN0b3JlX2VudW1zCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX3JlYWRfZW51bXNfcm91dGVAMzoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weToxNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIGNhbGxzdWIgcmVhZF9lbnVtcwogICAgYnl0ZSAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl9iYXJlX3JvdXRpbmdANjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weTo0CiAgICAvLyBjbGFzcyBCb3hDb250cmFjdChBUkM0Q29udHJhY3QpOgogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIHJlamVjdCB0cmFuc2FjdGlvbgogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgICEKICAgIGFzc2VydCAvLyBpcyBjcmVhdGluZwogICAgaW50IDEKICAgIHJldHVybgoKCi8vIHRlc3RzLmFydGlmYWN0cy5Cb3hDb250cmFjdC5jb250cmFjdC5Cb3hDb250cmFjdC5zdG9yZV9lbnVtcygpIC0+IHZvaWQ6CnN0b3JlX2VudW1zOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjktMTAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBkZWYgc3RvcmVfZW51bXMoc2VsZikgLT4gTm9uZToKICAgIHByb3RvIDAgMAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjExCiAgICAvLyBzZWxmLm9jYS52YWx1ZSA9IE9uQ29tcGxldGVBY3Rpb24uT3B0SW4KICAgIGludCBPcHRJbgogICAgaXRvYgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjYKICAgIC8vIHNlbGYub2NhID0gQm94KE9uQ29tcGxldGVBY3Rpb24pCiAgICBieXRlICJvY2EiCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvQm94Q29udHJhY3QvY29udHJhY3QucHk6MTEKICAgIC8vIHNlbGYub2NhLnZhbHVlID0gT25Db21wbGV0ZUFjdGlvbi5PcHRJbgogICAgc3dhcAogICAgYm94X3B1dAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjEyCiAgICAvLyBzZWxmLnR4bi52YWx1ZSA9IFRyYW5zYWN0aW9uVHlwZS5BcHBsaWNhdGlvbkNhbGwKICAgIGludCBhcHBsCiAgICBpdG9iCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvQm94Q29udHJhY3QvY29udHJhY3QucHk6NwogICAgLy8gc2VsZi50eG4gPSBCb3goVHJhbnNhY3Rpb25UeXBlKQogICAgYnl0ZSAidHhuIgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjEyCiAgICAvLyBzZWxmLnR4bi52YWx1ZSA9IFRyYW5zYWN0aW9uVHlwZS5BcHBsaWNhdGlvbkNhbGwKICAgIHN3YXAKICAgIGJveF9wdXQKICAgIHJldHN1YgoKCi8vIHRlc3RzLmFydGlmYWN0cy5Cb3hDb250cmFjdC5jb250cmFjdC5Cb3hDb250cmFjdC5yZWFkX2VudW1zKCkgLT4gYnl0ZXM6CnJlYWRfZW51bXM6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvQm94Q29udHJhY3QvY29udHJhY3QucHk6MTQtMTUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBkZWYgcmVhZF9lbnVtcyhzZWxmKSAtPiBhcmM0LlR1cGxlW2FyYzQuVUludDY0LCBhcmM0LlVJbnQ2NF06CiAgICBwcm90byAwIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weToxNgogICAgLy8gYXNzZXJ0IG9wLkJveC5nZXQoYiJvY2EiKVswXSA9PSBvcC5pdG9iKHNlbGYub2NhLnZhbHVlKQogICAgYnl0ZSAweDZmNjM2MQogICAgYm94X2dldAogICAgcG9wCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvQm94Q29udHJhY3QvY29udHJhY3QucHk6NgogICAgLy8gc2VsZi5vY2EgPSBCb3goT25Db21wbGV0ZUFjdGlvbikKICAgIGJ5dGUgIm9jYSIKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weToxNgogICAgLy8gYXNzZXJ0IG9wLkJveC5nZXQoYiJvY2EiKVswXSA9PSBvcC5pdG9iKHNlbGYub2NhLnZhbHVlKQogICAgYm94X2dldAogICAgc3dhcAogICAgYnRvaQogICAgc3dhcAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYub2NhIGV4aXN0cwogICAgaXRvYgogICAgPT0KICAgIGFzc2VydAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjE3CiAgICAvLyBhc3NlcnQgb3AuQm94LmdldChiInR4biIpWzBdID09IG9wLml0b2Ioc2VsZi50eG4udmFsdWUpCiAgICBieXRlIDB4NzQ3ODZlCiAgICBib3hfZ2V0CiAgICBwb3AKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weTo3CiAgICAvLyBzZWxmLnR4biA9IEJveChUcmFuc2FjdGlvblR5cGUpCiAgICBieXRlICJ0eG4iCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvQm94Q29udHJhY3QvY29udHJhY3QucHk6MTcKICAgIC8vIGFzc2VydCBvcC5Cb3guZ2V0KGIidHhuIilbMF0gPT0gb3AuaXRvYihzZWxmLnR4bi52YWx1ZSkKICAgIGJveF9nZXQKICAgIHN3YXAKICAgIGJ0b2kKICAgIHN3YXAKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLnR4biBleGlzdHMKICAgIGl0b2IKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weTo2CiAgICAvLyBzZWxmLm9jYSA9IEJveChPbkNvbXBsZXRlQWN0aW9uKQogICAgYnl0ZSAib2NhIgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjE5CiAgICAvLyByZXR1cm4gYXJjNC5UdXBsZSgoYXJjNC5VSW50NjQoc2VsZi5vY2EudmFsdWUpLCBhcmM0LlVJbnQ2NChzZWxmLnR4bi52YWx1ZSkpKQogICAgYm94X2dldAogICAgc3dhcAogICAgYnRvaQogICAgc3dhcAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYub2NhIGV4aXN0cwogICAgaXRvYgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL0JveENvbnRyYWN0L2NvbnRyYWN0LnB5OjcKICAgIC8vIHNlbGYudHhuID0gQm94KFRyYW5zYWN0aW9uVHlwZSkKICAgIGJ5dGUgInR4biIKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weToxOQogICAgLy8gcmV0dXJuIGFyYzQuVHVwbGUoKGFyYzQuVUludDY0KHNlbGYub2NhLnZhbHVlKSwgYXJjNC5VSW50NjQoc2VsZi50eG4udmFsdWUpKSkKICAgIGJveF9nZXQKICAgIHN3YXAKICAgIGJ0b2kKICAgIHN3YXAKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLnR4biBleGlzdHMKICAgIGl0b2IKICAgIGNvbmNhdAogICAgcmV0c3ViCg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgp0ZXN0cy5hcnRpZmFjdHMuQm94Q29udHJhY3QuY29udHJhY3QuQm94Q29udHJhY3QuY2xlYXJfc3RhdGVfcHJvZ3JhbToKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9Cb3hDb250cmFjdC9jb250cmFjdC5weTo0CiAgICAvLyBjbGFzcyBCb3hDb250cmFjdChBUkM0Q29udHJhY3QpOgogICAgaW50IDEKICAgIHJldHVybgo=" + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "schema": { + "global": { + "declared": {}, + "reserved": {} + }, + "local": { + "declared": {}, + "reserved": {} + } + }, + "contract": { + "name": "BoxContract", + "methods": [ + { + "name": "store_enums", + "args": [], + "readonly": false, + "returns": { + "type": "void" + } + }, + { + "name": "read_enums", + "args": [], + "readonly": false, + "returns": { + "type": "(uint64,uint64)" + } + } + ], + "networks": {} + }, + "bare_call_config": { + "no_op": "CREATE" + } +} \ No newline at end of file diff --git a/tests/artifacts/BoxContract/data/BoxContract.clear.teal b/tests/artifacts/BoxContract/data/BoxContract.clear.teal new file mode 100644 index 0000000..27c12e7 --- /dev/null +++ b/tests/artifacts/BoxContract/data/BoxContract.clear.teal @@ -0,0 +1,7 @@ +#pragma version 10 + +tests.artifacts.BoxContract.contract.BoxContract.clear_state_program: + // tests/artifacts/BoxContract/contract.py:4 + // class BoxContract(ARC4Contract): + int 1 + return diff --git a/tests/models/test_box.py b/tests/models/test_box.py index 321f11c..a8194c1 100644 --- a/tests/models/test_box.py +++ b/tests/models/test_box.py @@ -5,6 +5,7 @@ import pytest from algopy_testing import algopy_testing_context, arc4 from algopy_testing.context import AlgopyTestContext +from algopy_testing.op.pure import itob from algopy_testing.primitives.biguint import BigUInt from algopy_testing.primitives.bytes import Bytes from algopy_testing.primitives.string import String @@ -12,6 +13,8 @@ from algopy_testing.state.box import Box from algopy_testing.utils import as_bytes, as_string +from tests.artifacts.BoxContract.contract import BoxContract + BOX_NOT_CREATED_ERROR = "Box has not been created" @@ -22,10 +25,9 @@ def __init__(self) -> None: @pytest.fixture() def context() -> Generator[AlgopyTestContext, None, None]: - with algopy_testing_context() as ctx: + with algopy_testing_context() as ctx: # noqa: SIM117 with ctx.txn.create_group([ctx.any.txn.application_call()]): yield ctx - ctx.reset() def test_init_without_key( @@ -198,3 +200,19 @@ def _assert_box_content_equality( else: assert box_content == expected_value assert box_content == op_box_content + + +def test_enums_in_boxes(context: AlgopyTestContext) -> None: + # Arrange + contract = BoxContract() + + # Act + defered_store = context.txn.defer_app_call(contract.store_enums) + defered_read = context.txn.defer_app_call(contract.read_enums) + with context.txn.create_group([defered_store, defered_read]): + defered_store.submit() + oca, txn = defered_read.submit() + + # Assert + assert context.ledger.get_box(contract, b"oca") == itob(oca.native) + assert context.ledger.get_box(contract, b"txn") == itob(txn.native) diff --git a/tests/models/test_box_map.py b/tests/models/test_box_map.py index 8a42dab..f7ed52f 100644 --- a/tests/models/test_box_map.py +++ b/tests/models/test_box_map.py @@ -22,10 +22,9 @@ def __init__(self) -> None: @pytest.fixture() def context() -> Generator[AlgopyTestContext, None, None]: - with algopy_testing_context() as ctx: + with algopy_testing_context() as ctx: # noqa: SIM117 with ctx.txn.create_group([ctx.any.txn.application_call()]): yield ctx - ctx.reset() def test_init_without_key_prefix( diff --git a/tests/models/test_box_ref.py b/tests/models/test_box_ref.py index c9eed0e..ee09f00 100644 --- a/tests/models/test_box_ref.py +++ b/tests/models/test_box_ref.py @@ -21,10 +21,9 @@ def __init__(self) -> None: @pytest.fixture() def context() -> Generator[AlgopyTestContext, None, None]: - with algopy_testing_context() as ctx: + with algopy_testing_context() as ctx: # noqa: SIM117 with ctx.txn.create_group([ctx.any.txn.application_call()]): yield ctx - ctx.reset() def test_init_without_key( diff --git a/tests/state/test_global_state.py b/tests/state/test_global_state.py index 9cbbfa2..7160e02 100644 --- a/tests/state/test_global_state.py +++ b/tests/state/test_global_state.py @@ -13,7 +13,6 @@ def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() @pytest.mark.usefixtures("context") diff --git a/tests/test_op.py b/tests/test_op.py index 604b2a0..fcaf3e0 100644 --- a/tests/test_op.py +++ b/tests/test_op.py @@ -81,7 +81,6 @@ def _generate_ecdsa_test_data(curve: curves.Curve) -> dict[str, typing.Any]: def context() -> typing.Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() @pytest.fixture(scope="module") diff --git a/tests/utilities/test_log.py b/tests/utilities/test_log.py index 6beca3b..38f6d72 100644 --- a/tests/utilities/test_log.py +++ b/tests/utilities/test_log.py @@ -15,7 +15,6 @@ def context() -> Generator[AlgopyTestContext, None, None]: with algopy_testing_context() as ctx: yield ctx - ctx.reset() def test_log(get_avm_result: AVMInvoker, context: AlgopyTestContext) -> None: