• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CityOfZion / neo3-boa / 017024aa-199d-4642-8e92-e534b6134c2e

pending completion
017024aa-199d-4642-8e92-e534b6134c2e

Pull #1096

circleci

meevee98
#8678c423x - Update NeoTestRunner documentation on Neo3Boa
Pull Request #1096: Update NeoTestRunner usage in the documentation

19588 of 21344 relevant lines covered (91.77%)

2.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.9
/boa3/internal/model/builtin/classmethod/indexbytesstringmethod.py
1
import ast
3✔
2
from typing import Dict, List, Optional, Tuple
3✔
3

4
from boa3.internal.model.builtin.classmethod.indexmethod import IndexMethod
3✔
5
from boa3.internal.model.expression import IExpression
3✔
6
from boa3.internal.model.type.primitive.bytestype import BytesType
3✔
7
from boa3.internal.model.type.primitive.strtype import StrType
3✔
8
from boa3.internal.model.variable import Variable
3✔
9
from boa3.internal.neo.vm.opcode import OpcodeHelper
3✔
10
from boa3.internal.neo.vm.opcode.Opcode import Opcode
3✔
11
from boa3.internal.neo.vm.type.Integer import Integer
3✔
12
from boa3.internal.neo.vm.type.String import String
3✔
13

14

15
class IndexBytesStringMethod(IndexMethod):
3✔
16

17
    def __init__(self, self_type: Optional[StrType] = None):
3✔
18
        from boa3.internal.model.type.type import Type
3✔
19
        if not isinstance(self_type, (StrType, BytesType)):
3✔
20
            self_type = Type.str
3✔
21

22
        args: Dict[str, Variable] = {
3✔
23
            'self': Variable(self_type),
24
            'x': Variable(self_type),
25
            'start': Variable(Type.int),
26
            'end': Variable(Type.int),
27
        }
28

29
        start_default = ast.parse("{0}".format(0)
3✔
30
                                  ).body[0].value
31
        end_default = ast.parse("-1").body[0].value.operand
3✔
32
        end_default.n = -1
3✔
33

34
        super().__init__(args, defaults=[start_default, end_default])
3✔
35

36
    def validate_parameters(self, *params: IExpression) -> bool:
3✔
37
        if 2 <= len(params) <= 4:
×
38
            return False
×
39
        if not all(isinstance(param, IExpression) for param in params):
×
40
            return False
×
41

42
        from boa3.internal.model.type.itype import IType
×
43
        self_type: IType = params[0].type
×
44

45
        if not isinstance(self_type, (StrType, BytesType)):
×
46
            return False
×
47

48
        if not self_type.is_type_of(params[1]):
×
49
            return False
×
50

51
        return True
×
52

53
    @property
3✔
54
    def error_message(self) -> str:
3✔
55
        return 'substring not found' if isinstance(self._arg_self.type, StrType) else 'subsequence of bytes not found'
3✔
56

57
    @property
3✔
58
    def _opcode(self) -> List[Tuple[Opcode, bytes]]:
3✔
59
        from boa3.internal.compiler.codegenerator import get_bytes_count
3✔
60
        from boa3.internal.neo.vm.type.StackItem import StackItemType
3✔
61

62
        jmp_place_holder = (Opcode.JMP, b'\x01')
3✔
63
        message = String(self.error_message).to_bytes()
3✔
64

65
        # receives: end, start, substr, str
66
        verify_negative_index = [           # verifies if index in a negative value
3✔
67
            (Opcode.DUP, b''),
68
            (Opcode.PUSHM1, b''),
69
            jmp_place_holder                # if index >= 0, jump to verify_big_end or verify_big_start
70
        ]
71

72
        fix_negative_end = [                # gets the correspondent positive value of end
3✔
73
            (Opcode.PUSH3, b''),
74
            (Opcode.PICK, b''),
75
            (Opcode.SIZE, b''),
76
            (Opcode.ADD, b''),
77
            (Opcode.INC, b''),              # end = end + len(str) + 1
78
            (Opcode.DUP, b''),
79
            (Opcode.PUSHM1, b''),
80
            jmp_place_holder                # if end is not negative anymore, start verifying start
81
        ]
82

83
        fix_still_negative_index = [        # if index is still negative, consider it 0 then
3✔
84
            (Opcode.DROP, b''),
85
            (Opcode.PUSH0, b''),            # end = 0
86
        ]
87

88
        jmp_fix_negative_index = OpcodeHelper.get_jump_and_data(Opcode.JMPGT, get_bytes_count(fix_negative_end +
3✔
89
                                                                                              fix_still_negative_index), True)
90
        verify_negative_index[-1] = jmp_fix_negative_index
3✔
91

92
        verify_big_end = [                  # verify if end is bigger then len(str)
3✔
93
            (Opcode.DUP, b''),
94
            (Opcode.PUSH4, b''),
95
            (Opcode.PICK, b''),
96
            (Opcode.SIZE, b''),
97
            jmp_place_holder                # if end <= len(str), start verifying start
98
        ]
99

100
        fix_big_end = [                     # consider end as len(str)
3✔
101
            (Opcode.DROP, b''),
102
            (Opcode.PUSH2, b''),
103
            (Opcode.PICK, b''),
104
            (Opcode.SIZE, b''),             # end = len(str)
105
        ]
106

107
        jmp_other_verifies = OpcodeHelper.get_jump_and_data(Opcode.JMPGT, get_bytes_count(fix_still_negative_index +
3✔
108
                                                                                          verify_big_end +
109
                                                                                          fix_big_end), True)
110
        fix_negative_end[-1] = jmp_other_verifies
3✔
111

112
        jmp_fix_big_index = OpcodeHelper.get_jump_and_data(Opcode.JMPLE, get_bytes_count(fix_big_end), True)
3✔
113
        verify_big_end[-1] = jmp_fix_big_index
3✔
114

115
        verify_and_fix_end = [              # collection of Opcodes regarding verifying and fixing end index
3✔
116
            (Opcode.REVERSE4, b''),
117
        ]
118
        verify_and_fix_end.extend(verify_negative_index)
3✔
119
        verify_and_fix_end.extend(fix_negative_end)
3✔
120
        verify_and_fix_end.extend(fix_still_negative_index)
3✔
121
        verify_and_fix_end.extend(verify_big_end)
3✔
122
        verify_and_fix_end.extend(fix_big_end)
3✔
123

124
        verify_and_fix_start = [            # collection of Opcodes regarding verifying and fixing start index
3✔
125
            (Opcode.SWAP, b'')
126
        ]
127
        verify_and_fix_start.extend(verify_negative_index)
3✔
128
        verify_and_fix_start.extend(fix_negative_end)
3✔
129
        verify_and_fix_start.extend(fix_still_negative_index)
3✔
130
        verify_and_fix_start.extend(verify_big_end)
3✔
131
        verify_and_fix_start.extend(fix_big_end)
3✔
132

133
        change_stack_order = [              # change order of items on the stack
3✔
134
            (Opcode.PUSH2, b''),
135
            (Opcode.PICK, b''),
136
            (Opcode.SIZE, b''),             # size = len(substr)
137
            (Opcode.ROT, b''),
138
            (Opcode.ROT, b''),
139
        ]
140

141
        verify_while = [                    # verify already compared all that was need
3✔
142
            (Opcode.OVER, b''),
143
            (Opcode.OVER, b''),
144
            (Opcode.SUB, b''),
145
            (Opcode.PUSH3, b''),
146
            (Opcode.PICK, b''),
147
            jmp_place_holder                # if end - index >= size, jump to not_inside_sequence
148
        ]
149

150
        compare_item = [                    # compare str[index:index+size] with substr
3✔
151
            (Opcode.PUSH4, b''),
152
            (Opcode.PICK, b''),
153
            (Opcode.OVER, b''),
154
            (Opcode.PUSH4, b''),
155
            (Opcode.PICK, b''),
156
            (Opcode.SUBSTR, b''),
157
            (Opcode.CONVERT, StackItemType.ByteString),
158
            (Opcode.PUSH4, b''),
159
            (Opcode.PICK, b''),
160
            (Opcode.NUMEQUAL, b''),
161
            jmp_place_holder                # if str[index:index+size] == substr, return index
162
        ]
163

164
        not_found = [                       # increments index and goes back to verify again
3✔
165
            (Opcode.INC, b''),              # index++
166
            # jump to verify_while
167
        ]
168

169
        jmp_back_to_verify = OpcodeHelper.get_jump_and_data(Opcode.JMP, -get_bytes_count(verify_while +
3✔
170
                                                                                         compare_item +
171
                                                                                         not_found), True)
172
        not_found.append(jmp_back_to_verify)
3✔
173

174
        jmp_to_error = OpcodeHelper.get_jump_and_data(Opcode.JMPLT, get_bytes_count(compare_item +
3✔
175
                                                                                    not_found), True)
176
        verify_while[-1] = jmp_to_error
3✔
177

178
        not_inside_sequence = [             # send error message saying that substring not found
3✔
179
            (Opcode.PUSHDATA1, Integer(len(message)).to_byte_array(signed=True, min_length=1) + message),
180
            (Opcode.THROW, b''),
181
        ]
182

183
        jmp_to_return_index = OpcodeHelper.get_jump_and_data(Opcode.JMPIF, get_bytes_count(not_found +
3✔
184
                                                                                           not_inside_sequence), True)
185
        compare_item[-1] = jmp_to_return_index
3✔
186

187
        return_index = [                    # removes all values in the stack but the index
3✔
188
            (Opcode.NIP, b''),
189
            (Opcode.NIP, b''),
190
            (Opcode.NIP, b''),
191
            (Opcode.NIP, b''),
192
        ]
193

194
        return (
3✔
195
            verify_and_fix_end +
196
            verify_and_fix_start +
197
            change_stack_order +
198
            verify_while +
199
            compare_item +
200
            not_found +
201
            not_inside_sequence +
202
            return_index
203
        )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc