|
| 1 | +import re |
1 | 2 | import typing
|
2 | 3 | from collections.abc import Generator
|
3 | 4 |
|
4 |
| -import algopy |
5 | 5 | import pytest
|
| 6 | + |
| 7 | +import algopy |
6 | 8 | from _algopy_testing import algopy_testing_context, arc4
|
7 | 9 | from _algopy_testing.context import AlgopyTestContext
|
| 10 | +from _algopy_testing.models.account import Account |
| 11 | +from _algopy_testing.models.application import Application |
| 12 | +from _algopy_testing.models.asset import Asset |
8 | 13 | from _algopy_testing.op.pure import itob
|
9 | 14 | from _algopy_testing.primitives.biguint import BigUInt
|
10 | 15 | from _algopy_testing.primitives.bytes import Bytes
|
11 | 16 | from _algopy_testing.primitives.string import String
|
12 | 17 | from _algopy_testing.primitives.uint64 import UInt64
|
13 | 18 | from _algopy_testing.state.box import Box
|
| 19 | +from _algopy_testing.state.utils import cast_to_bytes |
14 | 20 | from _algopy_testing.utils import as_bytes, as_string
|
15 |
| - |
16 | 21 | from tests.artifacts.BoxContract.contract import BoxContract
|
17 | 22 |
|
18 | 23 | BOX_NOT_CREATED_ERROR = "Box has not been created"
|
19 | 24 |
|
20 | 25 |
|
| 26 | +class Swapped(arc4.Struct): |
| 27 | + b: arc4.UInt64 |
| 28 | + c: arc4.Bool |
| 29 | + d: arc4.Address |
| 30 | + |
| 31 | + |
| 32 | +# TODO: add tests for tuple and namedtuple once they are supported |
| 33 | +# class MyStruct(typing.NamedTuple): |
| 34 | +# a: UInt64 |
| 35 | +# b: bool |
| 36 | +# c: arc4.Bool |
| 37 | +# d: arc4.UInt64 |
| 38 | + |
| 39 | + |
21 | 40 | class ATestContract(algopy.Contract):
|
22 | 41 | def __init__(self) -> None:
|
23 | 42 | self.uint_64_box = algopy.Box(algopy.UInt64)
|
24 | 43 |
|
25 | 44 |
|
26 |
| -@pytest.fixture() |
| 45 | +@pytest.fixture |
27 | 46 | def context() -> Generator[AlgopyTestContext, None, None]:
|
28 | 47 | with algopy_testing_context() as ctx: # noqa: SIM117
|
29 | 48 | with ctx.txn.create_group([ctx.any.txn.application_call()]):
|
@@ -68,6 +87,126 @@ def test_init_with_key(
|
68 | 87 | _ = box.length
|
69 | 88 |
|
70 | 89 |
|
| 90 | +@pytest.mark.parametrize( |
| 91 | + ("value_type", "expected_size"), |
| 92 | + [ |
| 93 | + (arc4.UInt64, 8), |
| 94 | + (UInt64, 8), |
| 95 | + (arc4.Address, 32), |
| 96 | + (Account, 32), |
| 97 | + (Application, 8), |
| 98 | + (Asset, 8), |
| 99 | + (bool, 8), |
| 100 | + (arc4.StaticArray[arc4.Byte, typing.Literal[7]], 7), |
| 101 | + (Swapped, 41), |
| 102 | + # TODO: add tests for tuple and namedtuple once they are supported |
| 103 | + # (tuple[arc4.UInt64, arc4.Bool, arc4.Address], 41), |
| 104 | + # (MyStruct, 9), |
| 105 | + ], |
| 106 | +) |
| 107 | +def test_create_for_static_value_type( |
| 108 | + context: AlgopyTestContext, # noqa: ARG001 |
| 109 | + value_type: type, |
| 110 | + expected_size: int, |
| 111 | +) -> None: |
| 112 | + key = b"test_key" |
| 113 | + box = Box(value_type, key=key) # type: ignore[var-annotated] |
| 114 | + assert not box |
| 115 | + |
| 116 | + box.create() |
| 117 | + assert box |
| 118 | + |
| 119 | + op_box_content, op_box_exists = algopy.op.Box.get(key) |
| 120 | + assert op_box_exists |
| 121 | + assert op_box_content == b"\x00" * expected_size |
| 122 | + |
| 123 | + box_content, box_exists = box.maybe() |
| 124 | + assert box_exists |
| 125 | + assert cast_to_bytes(box_content) == b"\x00" * expected_size |
| 126 | + |
| 127 | + assert box.length == expected_size |
| 128 | + |
| 129 | + |
| 130 | +@pytest.mark.parametrize( |
| 131 | + ("value_type", "size", "expected_size"), |
| 132 | + [ |
| 133 | + (arc4.UInt64, 7, 8), |
| 134 | + (UInt64, 0, 8), |
| 135 | + (arc4.Address, 16, 32), |
| 136 | + (Account, 31, 32), |
| 137 | + (Application, 1, 8), |
| 138 | + (Asset, 0, 8), |
| 139 | + (bool, 1, 8), |
| 140 | + (arc4.StaticArray[arc4.Byte, typing.Literal[7]], 2, 7), |
| 141 | + ], |
| 142 | +) |
| 143 | +def test_create_smaller_box_for_static_value_type( |
| 144 | + context: AlgopyTestContext, # noqa: ARG001 |
| 145 | + value_type: type, |
| 146 | + size: int, |
| 147 | + expected_size: int, |
| 148 | +) -> None: |
| 149 | + key = b"test_key" |
| 150 | + box = Box(value_type, key=key) # type: ignore[var-annotated] |
| 151 | + assert not box |
| 152 | + |
| 153 | + with pytest.warns(UserWarning, match=f"Box size should not be less than {expected_size}"): |
| 154 | + box.create(size=size) |
| 155 | + |
| 156 | + |
| 157 | +@pytest.mark.parametrize( |
| 158 | + ("value_type", "size"), |
| 159 | + [ |
| 160 | + (arc4.String, 7), |
| 161 | + (arc4.DynamicArray[arc4.UInt64], 0), |
| 162 | + (arc4.DynamicArray[arc4.Address], 16), |
| 163 | + (Bytes, 31), |
| 164 | + (arc4.StaticArray[arc4.String, typing.Literal[7]], 2), |
| 165 | + ], |
| 166 | +) |
| 167 | +def test_create_box_for_dynamic_value_type( |
| 168 | + context: AlgopyTestContext, # noqa: ARG001 |
| 169 | + value_type: type, |
| 170 | + size: int, |
| 171 | +) -> None: |
| 172 | + key = b"test_key" |
| 173 | + box = Box(value_type, key=key) # type: ignore[var-annotated] |
| 174 | + assert not box |
| 175 | + |
| 176 | + box.create(size=size) |
| 177 | + |
| 178 | + op_box_content, op_box_exists = algopy.op.Box.get(key) |
| 179 | + assert op_box_exists |
| 180 | + assert op_box_content == b"\x00" * size |
| 181 | + |
| 182 | + assert box.length == size |
| 183 | + |
| 184 | + |
| 185 | +@pytest.mark.parametrize( |
| 186 | + "value_type", |
| 187 | + [ |
| 188 | + arc4.String, |
| 189 | + arc4.DynamicArray[arc4.UInt64], |
| 190 | + arc4.DynamicArray[arc4.Address], |
| 191 | + Bytes, |
| 192 | + arc4.StaticArray[arc4.String, typing.Literal[7]], |
| 193 | + ], |
| 194 | +) |
| 195 | +def test_create_box_for_dynamic_value_type_with_no_size( |
| 196 | + context: AlgopyTestContext, # noqa: ARG001 |
| 197 | + value_type: type, |
| 198 | +) -> None: |
| 199 | + key = b"test_key" |
| 200 | + box = Box(value_type, key=key) # type: ignore[var-annotated] |
| 201 | + assert not box |
| 202 | + |
| 203 | + with pytest.raises( |
| 204 | + ValueError, |
| 205 | + match=re.compile("does not have a fixed byte size. Please specify a size argument"), |
| 206 | + ): |
| 207 | + box.create() |
| 208 | + |
| 209 | + |
71 | 210 | @pytest.mark.parametrize(
|
72 | 211 | ("value_type", "value"),
|
73 | 212 | [
|
|
0 commit comments