Skip to content

Commit 5dce107

Browse files
committed
handle value of invalid length in bitwise operations
1 parent 4c9f97c commit 5dce107

File tree

2 files changed

+117
-94
lines changed

2 files changed

+117
-94
lines changed

src/_algopy_testing/primitives/fixed_bytes.py

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ class FixedBytes(
5656
):
5757
"""A statically-sized byte sequence, where the length is known at compile time.
5858
59-
Unlike `Bytes`, `FixedBytes` has a fixed length specified via a type parameter,
60-
allowing for compile-time validation and more efficient operations on the AVM.
59+
Unlike `Bytes`, `FixedBytes` has a fixed length specified via a type parameter.
6160
6261
Example:
6362
FixedBytes[typing.Literal[32]] # A 32-byte fixed-size bytes value
@@ -99,6 +98,9 @@ def __eq__(self, other: FixedBytes[_TBytesLength_Arg] | Bytes | bytes) -> bool:
9998
other_bytes = as_bytes(other)
10099
except TypeError:
101100
return NotImplemented
101+
102+
if isinstance(other, FixedBytes) and other.length != self.length:
103+
return False
102104
return self.value == other_bytes
103105

104106
def __hash__(self) -> int:
@@ -126,15 +128,16 @@ def __getitem__(
126128
) -> Bytes: # maps to substring/substring3 if slice, extract/extract3 otherwise?
127129
"""Returns a Bytes containing a single byte if indexed with UInt64 or int
128130
otherwise the substring o bytes described by the slice."""
131+
value = self.value[None : self.length]
129132
if isinstance(index, slice):
130-
return Bytes(self.value[index])
133+
return Bytes(value[index])
131134
else:
132135
int_index = index.value if isinstance(index, UInt64) else index
133-
int_index = len(self.value) + int_index if int_index < 0 else int_index
134-
if (int_index >= len(self.value)) or (int_index < 0):
136+
int_index = self.length.value + int_index if int_index < 0 else int_index
137+
if (int_index >= self.length) or (int_index < 0):
135138
raise ValueError("FixedBytes index out of range")
136139
# my_bytes[0:1] => b'j' whereas my_bytes[0] => 106
137-
return Bytes(self.value[slice(int_index, int_index + 1)])
140+
return Bytes(value[slice(int_index, int_index + 1)])
138141

139142
def __iter__(self) -> Iterator[Bytes]:
140143
"""FixedBytes can be iterated, yielding each consecutive byte."""
@@ -157,13 +160,7 @@ def __and__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> typin
157160
"""
158161
return self._operate_bitwise(other, "and_")
159162

160-
@typing.overload
161-
def __rand__(self, other: typing.Self) -> typing.Self: ... # type: ignore[overload-overlap]
162-
@typing.overload
163-
def __rand__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> Bytes: ...
164-
def __rand__(
165-
self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes
166-
) -> typing.Self | Bytes:
163+
def __rand__(self, other: bytes) -> Bytes:
167164
return self & other
168165

169166
def __iand__(self, other: Bytes | typing.Self | bytes) -> typing.Self: # type: ignore[misc]
@@ -180,11 +177,7 @@ def __or__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> Bytes:
180177
def __or__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> typing.Self | Bytes:
181178
return self._operate_bitwise(other, "or_")
182179

183-
@typing.overload
184-
def __ror__(self, other: typing.Self) -> typing.Self: ... # type: ignore[overload-overlap]
185-
@typing.overload
186-
def __ror__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> Bytes: ...
187-
def __ror__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> typing.Self | Bytes:
180+
def __ror__(self, other: bytes) -> Bytes:
188181
return self | other
189182

190183
def __ior__(self, other: Bytes | typing.Self | bytes) -> typing.Self: # type: ignore[misc]
@@ -201,13 +194,7 @@ def __xor__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> Bytes
201194
def __xor__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> typing.Self | Bytes:
202195
return self._operate_bitwise(other, "xor")
203196

204-
@typing.overload
205-
def __rxor__(self, other: typing.Self) -> typing.Self: ... # type: ignore[overload-overlap]
206-
@typing.overload
207-
def __rxor__(self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes) -> Bytes: ...
208-
def __rxor__(
209-
self, other: FixedBytes[_TBytesLength_Arg] | bytes | Bytes
210-
) -> typing.Self | Bytes:
197+
def __rxor__(self, other: bytes) -> Bytes:
211198
return self ^ other
212199

213200
def __ixor__(self, other: Bytes | typing.Self | bytes) -> typing.Self: # type: ignore[misc]
@@ -223,7 +210,7 @@ def __invert__(self) -> typing.Self:
223210
Returns:
224211
Bytes: The result of the bitwise inversion operation.
225212
"""
226-
return self.__class__(bytes(~x + 256 for x in self.value))
213+
return self.__class__.from_bytes(bytes(~x + 256 for x in self.value))
227214

228215
def _operate_bitwise(
229216
self,
@@ -244,7 +231,7 @@ def _operate_bitwise(
244231
)
245232
)
246233
if isinstance(other, FixedBytes) and len(other.value) == len(self.value):
247-
return self.__class__(result)
234+
return self.__class__.from_bytes(result)
248235
return Bytes(result)
249236

250237
def __contains__(self, item: FixedBytes[_TBytesLength_Arg] | Bytes | bytes) -> bool:

0 commit comments

Comments
 (0)