Fix: bt2: erroneous integer comparison of Field and Value
[babeltrace.git] / tests / bindings / python / bt2 / test_field.py
CommitLineData
d2d857a8
MJ
1#
2# Copyright (C) 2019 EfficiOS Inc.
3#
4# This program is free software; you can redistribute it and/or
5# modify it under the terms of the GNU General Public License
6# as published by the Free Software Foundation; only version 2
7# of the License.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17#
18
9cf643d1
PP
19from functools import partial, partialmethod
20import operator
21import unittest
9cf643d1
PP
22import math
23import copy
b0bdda42 24import itertools
9cf643d1 25import bt2
1eccc498 26from utils import get_default_trace_class
9cf643d1
PP
27
28
29_COMP_BINOPS = (
30 operator.eq,
31 operator.ne,
32)
33
34
1eccc498
SM
35# Create and return a stream with the field classes part of its stream packet
36# context.
37#
38# The stream is part of a dummy trace created from trace class `tc`.
39
40def _create_stream(tc, ctx_field_classes):
41 packet_context_fc = tc.create_structure_field_class()
42 for name, fc in ctx_field_classes:
43 packet_context_fc.append_member(name, fc)
44
45 trace = tc()
46 stream_class = tc.create_stream_class(packet_context_field_class=packet_context_fc)
47
48 stream = trace.create_stream(stream_class)
49 return stream
50
51
52# Create a field of the given field class.
53#
54# The field is part of a dummy stream, itself part of a dummy trace created
55# from trace class `tc`.
56
57def _create_field(tc, field_class):
58 field_name = 'field'
59 stream = _create_stream(tc, [(field_name, field_class)])
60 packet = stream.create_packet()
61 return packet.context_field[field_name]
62
63
64# Create a field of type string.
65#
66# The field is part of a dummy stream, itself part of a dummy trace created
67# from trace class `tc`. It is made out of a dummy string field class.
68
69def _create_string_field(tc):
70 field_name = 'string_field'
71 stream = _create_stream(tc, [(field_name, tc.create_string_field_class())])
72 packet = stream.create_packet()
73 return packet.context_field[field_name]
74
75
76# Create a field of type static array of ints.
77#
78# The field is part of a dummy stream, itself part of a dummy trace created
79# from trace class `tc`. It is made out of a dummy static array field class,
80# with a dummy integer field class as element class.
81
82def _create_int_array_field(tc, length):
83 elem_fc = tc.create_signed_integer_field_class(32)
84 fc = tc.create_static_array_field_class(elem_fc, length)
85 field_name = 'int_array'
86 stream = _create_stream(tc, [(field_name, fc)])
87 packet = stream.create_packet()
88 return packet.context_field[field_name]
89
90
91# Create a field of type dynamic array of ints.
92#
93# The field is part of a dummy stream, itself part of a dummy trace created
94# from trace class `tc`. It is made out of a dummy static array field class,
95# with a dummy integer field class as element and length classes.
96
97def _create_dynamic_array(tc):
98 elem_fc = tc.create_signed_integer_field_class(32)
99 len_fc = tc.create_signed_integer_field_class(32)
100 fc = tc.create_dynamic_array_field_class(elem_fc)
101 field_name = 'int_dyn_array'
102 stream = _create_stream(tc, [('thelength', len_fc), (field_name, fc)])
103 packet = stream.create_packet()
104 packet.context_field[field_name].length = 3
105 return packet.context_field[field_name]
106
107
108# Create a field of type array of (empty) structures.
109#
110# The field is part of a dummy stream, itself part of a dummy trace created
111# from trace class `tc`. It is made out of a dummy static array field class,
112# with a dummy struct field class as element class.
113
114def _create_struct_array_field(tc, length):
115 elem_fc = tc.create_structure_field_class()
116 fc = tc.create_static_array_field_class(elem_fc, length)
117 field_name = 'struct_array'
118 stream = _create_stream(tc, [(field_name, fc)])
119 packet = stream.create_packet()
120 return packet.context_field[field_name]
121
122
123class _TestNumericField:
9cf643d1
PP
124 def _binop(self, op, rhs):
125 rexc = None
126 rvexc = None
127 comp_value = rhs
128
9cf643d1
PP
129 try:
130 r = op(self._def, rhs)
131 except Exception as e:
132 rexc = e
133
134 try:
135 rv = op(self._def_value, comp_value)
136 except Exception as e:
137 rvexc = e
138
139 if rexc is not None or rvexc is not None:
140 # at least one of the operations raised an exception: in
141 # this case both operations should have raised the same
142 # type of exception (division by zero, bit shift with a
143 # floating point number operand, etc.)
144 self.assertIs(type(rexc), type(rvexc))
145 return None, None
146
147 return r, rv
148
149 def _unaryop(self, op):
150 rexc = None
151 rvexc = None
152
153 try:
154 r = op(self._def)
155 except Exception as e:
156 rexc = e
157
158 try:
159 rv = op(self._def_value)
160 except Exception as e:
161 rvexc = e
162
163 if rexc is not None or rvexc is not None:
164 # at least one of the operations raised an exception: in
165 # this case both operations should have raised the same
166 # type of exception (division by zero, bit shift with a
167 # floating point number operand, etc.)
168 self.assertIs(type(rexc), type(rvexc))
169 return None, None
170
171 return r, rv
172
173 def _test_unaryop_type(self, op):
174 r, rv = self._unaryop(op)
175
176 if r is None:
177 return
178
179 self.assertIsInstance(r, type(rv))
180
181 def _test_unaryop_value(self, op):
182 r, rv = self._unaryop(op)
183
184 if r is None:
185 return
186
187 self.assertEqual(r, rv)
188
189 def _test_unaryop_addr_same(self, op):
190 addr_before = self._def.addr
191 self._unaryop(op)
192 self.assertEqual(self._def.addr, addr_before)
193
194 def _test_unaryop_value_same(self, op):
e1c6bebd 195 value_before = copy.copy(self._def_value)
9cf643d1 196 self._unaryop(op)
e1c6bebd 197 self.assertEqual(self._def, value_before)
9cf643d1
PP
198
199 def _test_binop_type(self, op, rhs):
200 r, rv = self._binop(op, rhs)
201
202 if r is None:
203 return
204
205 if op in _COMP_BINOPS:
206 # __eq__() and __ne__() always return a 'bool' object
207 self.assertIsInstance(r, bool)
208 else:
209 self.assertIsInstance(r, type(rv))
210
211 def _test_binop_value(self, op, rhs):
212 r, rv = self._binop(op, rhs)
213
214 if r is None:
215 return
216
217 self.assertEqual(r, rv)
218
219 def _test_binop_lhs_addr_same(self, op, rhs):
220 addr_before = self._def.addr
221 r, rv = self._binop(op, rhs)
222 self.assertEqual(self._def.addr, addr_before)
223
1eccc498 224 @unittest.skip('copy is not implemented')
9cf643d1 225 def _test_binop_lhs_value_same(self, op, rhs):
e1c6bebd 226 value_before = copy.copy(self._def)
9cf643d1 227 r, rv = self._binop(op, rhs)
e1c6bebd 228 self.assertEqual(self._def, value_before)
9cf643d1
PP
229
230 def _test_binop_invalid_unknown(self, op):
231 if op in _COMP_BINOPS:
232 self.skipTest('not testing')
233
234 class A:
235 pass
236
237 with self.assertRaises(TypeError):
238 op(self._def, A())
239
240 def _test_binop_invalid_none(self, op):
241 if op in _COMP_BINOPS:
242 self.skipTest('not testing')
243
244 with self.assertRaises(TypeError):
245 op(self._def, None)
246
247 def _test_ibinop_value(self, op, rhs):
248 r, rv = self._binop(op, rhs)
249
250 if r is None:
251 return
252
253 # The inplace operators are special for field objects because
254 # they do not return a new, immutable object like it's the case
255 # for Python numbers. In Python, `a += 2`, where `a` is a number
256 # object, assigns a new number object reference to `a`, dropping
257 # the old reference. Since BT's field objects are mutable, we
258 # modify their internal value with the inplace operators. This
259 # means however that we can lose data in the process, for
260 # example:
261 #
262 # int_value_obj += 3.3
263 #
264 # Here, if `int_value_obj` is a Python `int` with the value 2,
265 # it would be a `float` object after this, holding the value
266 # 5.3. In our case, if `int_value_obj` is an integer field
267 # object, 3.3 is converted to an `int` object (3) and added to
268 # the current value of `int_value_obj`, so after this the value
269 # of the object is 5. This does not compare to 5.3, which is
270 # why we also use the `int()` type here.
c4239792 271 if isinstance(self._def, bt2.field._IntegerField):
9cf643d1
PP
272 rv = int(rv)
273
274 self.assertEqual(r, rv)
275
276 def _test_ibinop_type(self, op, rhs):
277 r, rv = self._binop(op, rhs)
278
279 if r is None:
280 return
281
282 self.assertIs(r, self._def)
283
284 def _test_ibinop_invalid_unknown(self, op):
285 class A:
286 pass
287
288 with self.assertRaises(TypeError):
289 op(self._def, A())
290
291 def _test_ibinop_invalid_none(self, op):
292 with self.assertRaises(TypeError):
293 op(self._def, None)
294
295 def _test_binop_rhs_false(self, test_cb, op):
296 test_cb(op, False)
297
298 def _test_binop_rhs_true(self, test_cb, op):
299 test_cb(op, True)
300
301 def _test_binop_rhs_pos_int(self, test_cb, op):
302 test_cb(op, 2)
303
304 def _test_binop_rhs_neg_int(self, test_cb, op):
305 test_cb(op, -23)
306
307 def _test_binop_rhs_zero_int(self, test_cb, op):
308 test_cb(op, 0)
309
310 def _test_binop_rhs_pos_vint(self, test_cb, op):
311 test_cb(op, bt2.create_value(2))
312
313 def _test_binop_rhs_neg_vint(self, test_cb, op):
314 test_cb(op, bt2.create_value(-23))
315
316 def _test_binop_rhs_zero_vint(self, test_cb, op):
317 test_cb(op, bt2.create_value(0))
318
319 def _test_binop_rhs_pos_float(self, test_cb, op):
320 test_cb(op, 2.2)
321
322 def _test_binop_rhs_neg_float(self, test_cb, op):
323 test_cb(op, -23.4)
324
325 def _test_binop_rhs_zero_float(self, test_cb, op):
326 test_cb(op, 0.0)
327
328 def _test_binop_rhs_pos_vfloat(self, test_cb, op):
329 test_cb(op, bt2.create_value(2.2))
330
331 def _test_binop_rhs_neg_vfloat(self, test_cb, op):
332 test_cb(op, bt2.create_value(-23.4))
333
334 def _test_binop_rhs_zero_vfloat(self, test_cb, op):
335 test_cb(op, bt2.create_value(0.0))
336
337 def _test_binop_type_false(self, op):
338 self._test_binop_rhs_false(self._test_binop_type, op)
339
340 def _test_binop_type_true(self, op):
341 self._test_binop_rhs_true(self._test_binop_type, op)
342
343 def _test_binop_type_pos_int(self, op):
344 self._test_binop_rhs_pos_int(self._test_binop_type, op)
345
346 def _test_binop_type_neg_int(self, op):
347 self._test_binop_rhs_neg_int(self._test_binop_type, op)
348
349 def _test_binop_type_zero_int(self, op):
350 self._test_binop_rhs_zero_int(self._test_binop_type, op)
351
352 def _test_binop_type_pos_vint(self, op):
353 self._test_binop_rhs_pos_vint(self._test_binop_type, op)
354
355 def _test_binop_type_neg_vint(self, op):
356 self._test_binop_rhs_neg_vint(self._test_binop_type, op)
357
358 def _test_binop_type_zero_vint(self, op):
359 self._test_binop_rhs_zero_vint(self._test_binop_type, op)
360
361 def _test_binop_type_pos_float(self, op):
362 self._test_binop_rhs_pos_float(self._test_binop_type, op)
363
364 def _test_binop_type_neg_float(self, op):
365 self._test_binop_rhs_neg_float(self._test_binop_type, op)
366
367 def _test_binop_type_zero_float(self, op):
368 self._test_binop_rhs_zero_float(self._test_binop_type, op)
369
370 def _test_binop_type_pos_vfloat(self, op):
371 self._test_binop_rhs_pos_vfloat(self._test_binop_type, op)
372
373 def _test_binop_type_neg_vfloat(self, op):
374 self._test_binop_rhs_neg_vfloat(self._test_binop_type, op)
375
376 def _test_binop_type_zero_vfloat(self, op):
377 self._test_binop_rhs_zero_vfloat(self._test_binop_type, op)
378
379 def _test_binop_value_false(self, op):
380 self._test_binop_rhs_false(self._test_binop_value, op)
381
382 def _test_binop_value_true(self, op):
383 self._test_binop_rhs_true(self._test_binop_value, op)
384
385 def _test_binop_value_pos_int(self, op):
386 self._test_binop_rhs_pos_int(self._test_binop_value, op)
387
388 def _test_binop_value_neg_int(self, op):
389 self._test_binop_rhs_neg_int(self._test_binop_value, op)
390
391 def _test_binop_value_zero_int(self, op):
392 self._test_binop_rhs_zero_int(self._test_binop_value, op)
393
394 def _test_binop_value_pos_vint(self, op):
395 self._test_binop_rhs_pos_vint(self._test_binop_value, op)
396
397 def _test_binop_value_neg_vint(self, op):
398 self._test_binop_rhs_neg_vint(self._test_binop_value, op)
399
400 def _test_binop_value_zero_vint(self, op):
401 self._test_binop_rhs_zero_vint(self._test_binop_value, op)
402
403 def _test_binop_value_pos_float(self, op):
404 self._test_binop_rhs_pos_float(self._test_binop_value, op)
405
406 def _test_binop_value_neg_float(self, op):
407 self._test_binop_rhs_neg_float(self._test_binop_value, op)
408
409 def _test_binop_value_zero_float(self, op):
410 self._test_binop_rhs_zero_float(self._test_binop_value, op)
411
412 def _test_binop_value_pos_vfloat(self, op):
413 self._test_binop_rhs_pos_vfloat(self._test_binop_value, op)
414
415 def _test_binop_value_neg_vfloat(self, op):
416 self._test_binop_rhs_neg_vfloat(self._test_binop_value, op)
417
418 def _test_binop_value_zero_vfloat(self, op):
419 self._test_binop_rhs_zero_vfloat(self._test_binop_value, op)
420
421 def _test_binop_lhs_addr_same_false(self, op):
422 self._test_binop_rhs_false(self._test_binop_lhs_addr_same, op)
423
424 def _test_binop_lhs_addr_same_true(self, op):
425 self._test_binop_rhs_true(self._test_binop_lhs_addr_same, op)
426
427 def _test_binop_lhs_addr_same_pos_int(self, op):
428 self._test_binop_rhs_pos_int(self._test_binop_lhs_addr_same, op)
429
430 def _test_binop_lhs_addr_same_neg_int(self, op):
431 self._test_binop_rhs_neg_int(self._test_binop_lhs_addr_same, op)
432
433 def _test_binop_lhs_addr_same_zero_int(self, op):
434 self._test_binop_rhs_zero_int(self._test_binop_lhs_addr_same, op)
435
436 def _test_binop_lhs_addr_same_pos_vint(self, op):
437 self._test_binop_rhs_pos_vint(self._test_binop_lhs_addr_same, op)
438
439 def _test_binop_lhs_addr_same_neg_vint(self, op):
440 self._test_binop_rhs_neg_vint(self._test_binop_lhs_addr_same, op)
441
442 def _test_binop_lhs_addr_same_zero_vint(self, op):
443 self._test_binop_rhs_zero_vint(self._test_binop_lhs_addr_same, op)
444
445 def _test_binop_lhs_addr_same_pos_float(self, op):
446 self._test_binop_rhs_pos_float(self._test_binop_lhs_addr_same, op)
447
448 def _test_binop_lhs_addr_same_neg_float(self, op):
449 self._test_binop_rhs_neg_float(self._test_binop_lhs_addr_same, op)
450
451 def _test_binop_lhs_addr_same_zero_float(self, op):
452 self._test_binop_rhs_zero_float(self._test_binop_lhs_addr_same, op)
453
454 def _test_binop_lhs_addr_same_pos_vfloat(self, op):
455 self._test_binop_rhs_pos_vfloat(self._test_binop_lhs_addr_same, op)
456
457 def _test_binop_lhs_addr_same_neg_vfloat(self, op):
458 self._test_binop_rhs_neg_vfloat(self._test_binop_lhs_addr_same, op)
459
460 def _test_binop_lhs_addr_same_zero_vfloat(self, op):
461 self._test_binop_rhs_zero_vfloat(self._test_binop_lhs_addr_same, op)
462
463 def _test_binop_lhs_value_same_false(self, op):
464 self._test_binop_rhs_false(self._test_binop_lhs_value_same, op)
465
466 def _test_binop_lhs_value_same_true(self, op):
467 self._test_binop_rhs_true(self._test_binop_lhs_value_same, op)
468
469 def _test_binop_lhs_value_same_pos_int(self, op):
470 self._test_binop_rhs_pos_int(self._test_binop_lhs_value_same, op)
471
472 def _test_binop_lhs_value_same_neg_int(self, op):
473 self._test_binop_rhs_neg_int(self._test_binop_lhs_value_same, op)
474
475 def _test_binop_lhs_value_same_zero_int(self, op):
476 self._test_binop_rhs_zero_int(self._test_binop_lhs_value_same, op)
477
478 def _test_binop_lhs_value_same_pos_vint(self, op):
479 self._test_binop_rhs_pos_vint(self._test_binop_lhs_value_same, op)
480
481 def _test_binop_lhs_value_same_neg_vint(self, op):
482 self._test_binop_rhs_neg_vint(self._test_binop_lhs_value_same, op)
483
484 def _test_binop_lhs_value_same_zero_vint(self, op):
485 self._test_binop_rhs_zero_vint(self._test_binop_lhs_value_same, op)
486
487 def _test_binop_lhs_value_same_pos_float(self, op):
488 self._test_binop_rhs_pos_float(self._test_binop_lhs_value_same, op)
489
490 def _test_binop_lhs_value_same_neg_float(self, op):
491 self._test_binop_rhs_neg_float(self._test_binop_lhs_value_same, op)
492
493 def _test_binop_lhs_value_same_zero_float(self, op):
494 self._test_binop_rhs_zero_float(self._test_binop_lhs_value_same, op)
495
496 def _test_binop_lhs_value_same_pos_vfloat(self, op):
497 self._test_binop_rhs_pos_vfloat(self._test_binop_lhs_value_same, op)
498
499 def _test_binop_lhs_value_same_neg_vfloat(self, op):
500 self._test_binop_rhs_neg_vfloat(self._test_binop_lhs_value_same, op)
501
502 def _test_binop_lhs_value_same_zero_vfloat(self, op):
503 self._test_binop_rhs_zero_vfloat(self._test_binop_lhs_value_same, op)
504
505 def _test_ibinop_type_false(self, op):
506 self._test_binop_rhs_false(self._test_ibinop_type, op)
507
508 def _test_ibinop_type_true(self, op):
509 self._test_binop_rhs_true(self._test_ibinop_type, op)
510
511 def _test_ibinop_type_pos_int(self, op):
512 self._test_binop_rhs_pos_int(self._test_ibinop_type, op)
513
514 def _test_ibinop_type_neg_int(self, op):
515 self._test_binop_rhs_neg_int(self._test_ibinop_type, op)
516
517 def _test_ibinop_type_zero_int(self, op):
518 self._test_binop_rhs_zero_int(self._test_ibinop_type, op)
519
520 def _test_ibinop_type_pos_vint(self, op):
521 self._test_binop_rhs_pos_vint(self._test_ibinop_type, op)
522
523 def _test_ibinop_type_neg_vint(self, op):
524 self._test_binop_rhs_neg_vint(self._test_ibinop_type, op)
525
526 def _test_ibinop_type_zero_vint(self, op):
527 self._test_binop_rhs_zero_vint(self._test_ibinop_type, op)
528
529 def _test_ibinop_type_pos_float(self, op):
530 self._test_binop_rhs_pos_float(self._test_ibinop_type, op)
531
532 def _test_ibinop_type_neg_float(self, op):
533 self._test_binop_rhs_neg_float(self._test_ibinop_type, op)
534
535 def _test_ibinop_type_zero_float(self, op):
536 self._test_binop_rhs_zero_float(self._test_ibinop_type, op)
537
538 def _test_ibinop_type_pos_vfloat(self, op):
539 self._test_binop_rhs_pos_vfloat(self._test_ibinop_type, op)
540
541 def _test_ibinop_type_neg_vfloat(self, op):
542 self._test_binop_rhs_neg_vfloat(self._test_ibinop_type, op)
543
544 def _test_ibinop_type_zero_vfloat(self, op):
545 self._test_binop_rhs_zero_vfloat(self._test_ibinop_type, op)
546
547 def _test_ibinop_value_false(self, op):
548 self._test_binop_rhs_false(self._test_ibinop_value, op)
549
550 def _test_ibinop_value_true(self, op):
551 self._test_binop_rhs_true(self._test_ibinop_value, op)
552
553 def _test_ibinop_value_pos_int(self, op):
554 self._test_binop_rhs_pos_int(self._test_ibinop_value, op)
555
556 def _test_ibinop_value_neg_int(self, op):
557 self._test_binop_rhs_neg_int(self._test_ibinop_value, op)
558
559 def _test_ibinop_value_zero_int(self, op):
560 self._test_binop_rhs_zero_int(self._test_ibinop_value, op)
561
562 def _test_ibinop_value_pos_vint(self, op):
563 self._test_binop_rhs_pos_vint(self._test_ibinop_value, op)
564
565 def _test_ibinop_value_neg_vint(self, op):
566 self._test_binop_rhs_neg_vint(self._test_ibinop_value, op)
567
568 def _test_ibinop_value_zero_vint(self, op):
569 self._test_binop_rhs_zero_vint(self._test_ibinop_value, op)
570
571 def _test_ibinop_value_pos_float(self, op):
572 self._test_binop_rhs_pos_float(self._test_ibinop_value, op)
573
574 def _test_ibinop_value_neg_float(self, op):
575 self._test_binop_rhs_neg_float(self._test_ibinop_value, op)
576
577 def _test_ibinop_value_zero_float(self, op):
578 self._test_binop_rhs_zero_float(self._test_ibinop_value, op)
579
580 def _test_ibinop_value_pos_vfloat(self, op):
581 self._test_binop_rhs_pos_vfloat(self._test_ibinop_value, op)
582
583 def _test_ibinop_value_neg_vfloat(self, op):
584 self._test_binop_rhs_neg_vfloat(self._test_ibinop_value, op)
585
586 def _test_ibinop_value_zero_vfloat(self, op):
587 self._test_binop_rhs_zero_vfloat(self._test_ibinop_value, op)
588
589 def test_bool_op(self):
590 self.assertEqual(bool(self._def), bool(self._def_value))
591
592 def test_int_op(self):
593 self.assertEqual(int(self._def), int(self._def_value))
594
595 def test_float_op(self):
596 self.assertEqual(float(self._def), float(self._def_value))
597
598 def test_complex_op(self):
599 self.assertEqual(complex(self._def), complex(self._def_value))
600
601 def test_str_op(self):
602 self.assertEqual(str(self._def), str(self._def_value))
603
604 def test_eq_none(self):
1eccc498
SM
605 # Ignore this lint error:
606 # E711 comparison to None should be 'if cond is None:'
607 # since this is what we want to test (even though not good practice).
608 self.assertFalse(self._def == None) # noqa: E711
9cf643d1
PP
609
610 def test_ne_none(self):
1eccc498
SM
611 # Ignore this lint error:
612 # E711 comparison to None should be 'if cond is not None:'
613 # since this is what we want to test (even though not good practice).
614 self.assertTrue(self._def != None) # noqa: E711
742e4747 615
9cf643d1
PP
616
617_BINOPS = (
618 ('lt', operator.lt),
619 ('le', operator.le),
620 ('eq', operator.eq),
621 ('ne', operator.ne),
622 ('ge', operator.ge),
623 ('gt', operator.gt),
624 ('add', operator.add),
625 ('radd', lambda a, b: operator.add(b, a)),
626 ('and', operator.and_),
627 ('rand', lambda a, b: operator.and_(b, a)),
628 ('floordiv', operator.floordiv),
629 ('rfloordiv', lambda a, b: operator.floordiv(b, a)),
630 ('lshift', operator.lshift),
631 ('rlshift', lambda a, b: operator.lshift(b, a)),
632 ('mod', operator.mod),
633 ('rmod', lambda a, b: operator.mod(b, a)),
634 ('mul', operator.mul),
635 ('rmul', lambda a, b: operator.mul(b, a)),
636 ('or', operator.or_),
637 ('ror', lambda a, b: operator.or_(b, a)),
638 ('pow', operator.pow),
639 ('rpow', lambda a, b: operator.pow(b, a)),
640 ('rshift', operator.rshift),
641 ('rrshift', lambda a, b: operator.rshift(b, a)),
642 ('sub', operator.sub),
643 ('rsub', lambda a, b: operator.sub(b, a)),
644 ('truediv', operator.truediv),
645 ('rtruediv', lambda a, b: operator.truediv(b, a)),
646 ('xor', operator.xor),
647 ('rxor', lambda a, b: operator.xor(b, a)),
648)
649
650
651_IBINOPS = (
652 ('iadd', operator.iadd),
653 ('iand', operator.iand),
654 ('ifloordiv', operator.ifloordiv),
655 ('ilshift', operator.ilshift),
656 ('imod', operator.imod),
657 ('imul', operator.imul),
658 ('ior', operator.ior),
659 ('ipow', operator.ipow),
660 ('irshift', operator.irshift),
661 ('isub', operator.isub),
662 ('itruediv', operator.itruediv),
663 ('ixor', operator.ixor),
664)
665
666
667_UNARYOPS = (
668 ('neg', operator.neg),
669 ('pos', operator.pos),
670 ('abs', operator.abs),
671 ('invert', operator.invert),
672 ('round', round),
673 ('round_0', partial(round, ndigits=0)),
674 ('round_1', partial(round, ndigits=1)),
675 ('round_2', partial(round, ndigits=2)),
676 ('round_3', partial(round, ndigits=3)),
677 ('ceil', math.ceil),
678 ('floor', math.floor),
679 ('trunc', math.trunc),
680)
681
682
683def _inject_numeric_testing_methods(cls):
684 def test_binop_name(suffix):
685 return 'test_binop_{}_{}'.format(name, suffix)
686
687 def test_ibinop_name(suffix):
688 return 'test_ibinop_{}_{}'.format(name, suffix)
689
690 def test_unaryop_name(suffix):
691 return 'test_unaryop_{}_{}'.format(name, suffix)
692
693 # inject testing methods for each binary operation
694 for name, binop in _BINOPS:
9cf643d1
PP
695 setattr(cls, test_binop_name('invalid_unknown'), partialmethod(_TestNumericField._test_binop_invalid_unknown, op=binop))
696 setattr(cls, test_binop_name('invalid_none'), partialmethod(_TestNumericField._test_binop_invalid_none, op=binop))
697 setattr(cls, test_binop_name('type_true'), partialmethod(_TestNumericField._test_binop_type_true, op=binop))
698 setattr(cls, test_binop_name('type_pos_int'), partialmethod(_TestNumericField._test_binop_type_pos_int, op=binop))
699 setattr(cls, test_binop_name('type_pos_vint'), partialmethod(_TestNumericField._test_binop_type_pos_vint, op=binop))
700 setattr(cls, test_binop_name('value_true'), partialmethod(_TestNumericField._test_binop_value_true, op=binop))
701 setattr(cls, test_binop_name('value_pos_int'), partialmethod(_TestNumericField._test_binop_value_pos_int, op=binop))
702 setattr(cls, test_binop_name('value_pos_vint'), partialmethod(_TestNumericField._test_binop_value_pos_vint, op=binop))
703 setattr(cls, test_binop_name('lhs_addr_same_true'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_true, op=binop))
704 setattr(cls, test_binop_name('lhs_addr_same_pos_int'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_pos_int, op=binop))
705 setattr(cls, test_binop_name('lhs_addr_same_pos_vint'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_pos_vint, op=binop))
706 setattr(cls, test_binop_name('lhs_value_same_true'), partialmethod(_TestNumericField._test_binop_lhs_value_same_true, op=binop))
707 setattr(cls, test_binop_name('lhs_value_same_pos_int'), partialmethod(_TestNumericField._test_binop_lhs_value_same_pos_int, op=binop))
708 setattr(cls, test_binop_name('lhs_value_same_pos_vint'), partialmethod(_TestNumericField._test_binop_lhs_value_same_pos_vint, op=binop))
709 setattr(cls, test_binop_name('type_neg_int'), partialmethod(_TestNumericField._test_binop_type_neg_int, op=binop))
710 setattr(cls, test_binop_name('type_neg_vint'), partialmethod(_TestNumericField._test_binop_type_neg_vint, op=binop))
711 setattr(cls, test_binop_name('value_neg_int'), partialmethod(_TestNumericField._test_binop_value_neg_int, op=binop))
712 setattr(cls, test_binop_name('value_neg_vint'), partialmethod(_TestNumericField._test_binop_value_neg_vint, op=binop))
713 setattr(cls, test_binop_name('lhs_addr_same_neg_int'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_neg_int, op=binop))
714 setattr(cls, test_binop_name('lhs_addr_same_neg_vint'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_neg_vint, op=binop))
715 setattr(cls, test_binop_name('lhs_value_same_neg_int'), partialmethod(_TestNumericField._test_binop_lhs_value_same_neg_int, op=binop))
716 setattr(cls, test_binop_name('lhs_value_same_neg_vint'), partialmethod(_TestNumericField._test_binop_lhs_value_same_neg_vint, op=binop))
717 setattr(cls, test_binop_name('type_false'), partialmethod(_TestNumericField._test_binop_type_false, op=binop))
718 setattr(cls, test_binop_name('type_zero_int'), partialmethod(_TestNumericField._test_binop_type_zero_int, op=binop))
719 setattr(cls, test_binop_name('type_zero_vint'), partialmethod(_TestNumericField._test_binop_type_zero_vint, op=binop))
720 setattr(cls, test_binop_name('value_false'), partialmethod(_TestNumericField._test_binop_value_false, op=binop))
721 setattr(cls, test_binop_name('value_zero_int'), partialmethod(_TestNumericField._test_binop_value_zero_int, op=binop))
722 setattr(cls, test_binop_name('value_zero_vint'), partialmethod(_TestNumericField._test_binop_value_zero_vint, op=binop))
723 setattr(cls, test_binop_name('lhs_addr_same_false'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_false, op=binop))
724 setattr(cls, test_binop_name('lhs_addr_same_zero_int'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_zero_int, op=binop))
725 setattr(cls, test_binop_name('lhs_addr_same_zero_vint'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_zero_vint, op=binop))
726 setattr(cls, test_binop_name('lhs_value_same_false'), partialmethod(_TestNumericField._test_binop_lhs_value_same_false, op=binop))
727 setattr(cls, test_binop_name('lhs_value_same_zero_int'), partialmethod(_TestNumericField._test_binop_lhs_value_same_zero_int, op=binop))
728 setattr(cls, test_binop_name('lhs_value_same_zero_vint'), partialmethod(_TestNumericField._test_binop_lhs_value_same_zero_vint, op=binop))
729 setattr(cls, test_binop_name('type_pos_float'), partialmethod(_TestNumericField._test_binop_type_pos_float, op=binop))
730 setattr(cls, test_binop_name('type_neg_float'), partialmethod(_TestNumericField._test_binop_type_neg_float, op=binop))
731 setattr(cls, test_binop_name('type_pos_vfloat'), partialmethod(_TestNumericField._test_binop_type_pos_vfloat, op=binop))
732 setattr(cls, test_binop_name('type_neg_vfloat'), partialmethod(_TestNumericField._test_binop_type_neg_vfloat, op=binop))
733 setattr(cls, test_binop_name('value_pos_float'), partialmethod(_TestNumericField._test_binop_value_pos_float, op=binop))
734 setattr(cls, test_binop_name('value_neg_float'), partialmethod(_TestNumericField._test_binop_value_neg_float, op=binop))
735 setattr(cls, test_binop_name('value_pos_vfloat'), partialmethod(_TestNumericField._test_binop_value_pos_vfloat, op=binop))
736 setattr(cls, test_binop_name('value_neg_vfloat'), partialmethod(_TestNumericField._test_binop_value_neg_vfloat, op=binop))
737 setattr(cls, test_binop_name('lhs_addr_same_pos_float'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_pos_float, op=binop))
738 setattr(cls, test_binop_name('lhs_addr_same_neg_float'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_neg_float, op=binop))
739 setattr(cls, test_binop_name('lhs_addr_same_pos_vfloat'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_pos_vfloat, op=binop))
740 setattr(cls, test_binop_name('lhs_addr_same_neg_vfloat'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_neg_vfloat, op=binop))
741 setattr(cls, test_binop_name('lhs_value_same_pos_float'), partialmethod(_TestNumericField._test_binop_lhs_value_same_pos_float, op=binop))
742 setattr(cls, test_binop_name('lhs_value_same_neg_float'), partialmethod(_TestNumericField._test_binop_lhs_value_same_neg_float, op=binop))
743 setattr(cls, test_binop_name('lhs_value_same_pos_vfloat'), partialmethod(_TestNumericField._test_binop_lhs_value_same_pos_vfloat, op=binop))
744 setattr(cls, test_binop_name('lhs_value_same_neg_vfloat'), partialmethod(_TestNumericField._test_binop_lhs_value_same_neg_vfloat, op=binop))
745 setattr(cls, test_binop_name('type_zero_float'), partialmethod(_TestNumericField._test_binop_type_zero_float, op=binop))
746 setattr(cls, test_binop_name('type_zero_vfloat'), partialmethod(_TestNumericField._test_binop_type_zero_vfloat, op=binop))
747 setattr(cls, test_binop_name('value_zero_float'), partialmethod(_TestNumericField._test_binop_value_zero_float, op=binop))
748 setattr(cls, test_binop_name('value_zero_vfloat'), partialmethod(_TestNumericField._test_binop_value_zero_vfloat, op=binop))
749 setattr(cls, test_binop_name('lhs_addr_same_zero_float'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_zero_float, op=binop))
750 setattr(cls, test_binop_name('lhs_addr_same_zero_vfloat'), partialmethod(_TestNumericField._test_binop_lhs_addr_same_zero_vfloat, op=binop))
751 setattr(cls, test_binop_name('lhs_value_same_zero_float'), partialmethod(_TestNumericField._test_binop_lhs_value_same_zero_float, op=binop))
752 setattr(cls, test_binop_name('lhs_value_same_zero_vfloat'), partialmethod(_TestNumericField._test_binop_lhs_value_same_zero_vfloat, op=binop))
753
754 # inject testing methods for each unary operation
755 for name, unaryop in _UNARYOPS:
756 setattr(cls, test_unaryop_name('type'), partialmethod(_TestNumericField._test_unaryop_type, op=unaryop))
757 setattr(cls, test_unaryop_name('value'), partialmethod(_TestNumericField._test_unaryop_value, op=unaryop))
758 setattr(cls, test_unaryop_name('addr_same'), partialmethod(_TestNumericField._test_unaryop_addr_same, op=unaryop))
759 setattr(cls, test_unaryop_name('value_same'), partialmethod(_TestNumericField._test_unaryop_value_same, op=unaryop))
760
761 # inject testing methods for each inplace binary operation
762 for name, ibinop in _IBINOPS:
763 setattr(cls, test_ibinop_name('invalid_unknown'), partialmethod(_TestNumericField._test_ibinop_invalid_unknown, op=ibinop))
764 setattr(cls, test_ibinop_name('invalid_none'), partialmethod(_TestNumericField._test_ibinop_invalid_none, op=ibinop))
765 setattr(cls, test_ibinop_name('type_true'), partialmethod(_TestNumericField._test_ibinop_type_true, op=ibinop))
766 setattr(cls, test_ibinop_name('value_true'), partialmethod(_TestNumericField._test_ibinop_value_true, op=ibinop))
767 setattr(cls, test_ibinop_name('type_pos_int'), partialmethod(_TestNumericField._test_ibinop_type_pos_int, op=ibinop))
768 setattr(cls, test_ibinop_name('type_pos_vint'), partialmethod(_TestNumericField._test_ibinop_type_pos_vint, op=ibinop))
769 setattr(cls, test_ibinop_name('value_pos_int'), partialmethod(_TestNumericField._test_ibinop_value_pos_int, op=ibinop))
770 setattr(cls, test_ibinop_name('value_pos_vint'), partialmethod(_TestNumericField._test_ibinop_value_pos_vint, op=ibinop))
771 setattr(cls, test_ibinop_name('type_neg_int'), partialmethod(_TestNumericField._test_ibinop_type_neg_int, op=ibinop))
772 setattr(cls, test_ibinop_name('type_neg_vint'), partialmethod(_TestNumericField._test_ibinop_type_neg_vint, op=ibinop))
773 setattr(cls, test_ibinop_name('value_neg_int'), partialmethod(_TestNumericField._test_ibinop_value_neg_int, op=ibinop))
774 setattr(cls, test_ibinop_name('value_neg_vint'), partialmethod(_TestNumericField._test_ibinop_value_neg_vint, op=ibinop))
775 setattr(cls, test_ibinop_name('type_false'), partialmethod(_TestNumericField._test_ibinop_type_false, op=ibinop))
776 setattr(cls, test_ibinop_name('value_false'), partialmethod(_TestNumericField._test_ibinop_value_false, op=ibinop))
777 setattr(cls, test_ibinop_name('type_zero_int'), partialmethod(_TestNumericField._test_ibinop_type_zero_int, op=ibinop))
778 setattr(cls, test_ibinop_name('type_zero_vint'), partialmethod(_TestNumericField._test_ibinop_type_zero_vint, op=ibinop))
779 setattr(cls, test_ibinop_name('value_zero_int'), partialmethod(_TestNumericField._test_ibinop_value_zero_int, op=ibinop))
780 setattr(cls, test_ibinop_name('value_zero_vint'), partialmethod(_TestNumericField._test_ibinop_value_zero_vint, op=ibinop))
781 setattr(cls, test_ibinop_name('type_pos_float'), partialmethod(_TestNumericField._test_ibinop_type_pos_float, op=ibinop))
782 setattr(cls, test_ibinop_name('type_neg_float'), partialmethod(_TestNumericField._test_ibinop_type_neg_float, op=ibinop))
783 setattr(cls, test_ibinop_name('type_pos_vfloat'), partialmethod(_TestNumericField._test_ibinop_type_pos_vfloat, op=ibinop))
784 setattr(cls, test_ibinop_name('type_neg_vfloat'), partialmethod(_TestNumericField._test_ibinop_type_neg_vfloat, op=ibinop))
785 setattr(cls, test_ibinop_name('value_pos_float'), partialmethod(_TestNumericField._test_ibinop_value_pos_float, op=ibinop))
786 setattr(cls, test_ibinop_name('value_neg_float'), partialmethod(_TestNumericField._test_ibinop_value_neg_float, op=ibinop))
787 setattr(cls, test_ibinop_name('value_pos_vfloat'), partialmethod(_TestNumericField._test_ibinop_value_pos_vfloat, op=ibinop))
788 setattr(cls, test_ibinop_name('value_neg_vfloat'), partialmethod(_TestNumericField._test_ibinop_value_neg_vfloat, op=ibinop))
789 setattr(cls, test_ibinop_name('type_zero_float'), partialmethod(_TestNumericField._test_ibinop_type_zero_float, op=ibinop))
790 setattr(cls, test_ibinop_name('type_zero_vfloat'), partialmethod(_TestNumericField._test_ibinop_type_zero_vfloat, op=ibinop))
791 setattr(cls, test_ibinop_name('value_zero_float'), partialmethod(_TestNumericField._test_ibinop_value_zero_float, op=ibinop))
792 setattr(cls, test_ibinop_name('value_zero_vfloat'), partialmethod(_TestNumericField._test_ibinop_value_zero_vfloat, op=ibinop))
793
794
795class _TestIntegerFieldCommon(_TestNumericField):
796 def test_assign_true(self):
797 raw = True
798 self._def.value = raw
799 self.assertEqual(self._def, raw)
9cf643d1
PP
800
801 def test_assign_false(self):
802 raw = False
803 self._def.value = raw
804 self.assertEqual(self._def, raw)
9cf643d1
PP
805
806 def test_assign_pos_int(self):
807 raw = 477
808 self._def.value = raw
809 self.assertEqual(self._def, raw)
9cf643d1
PP
810
811 def test_assign_neg_int(self):
812 raw = -13
813 self._def.value = raw
814 self.assertEqual(self._def, raw)
9cf643d1
PP
815
816 def test_assign_int_field(self):
817 raw = 999
1eccc498 818 field = _create_field(self._tc, self._create_fc(self._tc))
9cf643d1
PP
819 field.value = raw
820 self._def.value = field
821 self.assertEqual(self._def, raw)
9cf643d1
PP
822
823 def test_assign_float(self):
824 raw = 123.456
825 self._def.value = raw
826 self.assertEqual(self._def, int(raw))
9cf643d1
PP
827
828 def test_assign_invalid_type(self):
829 with self.assertRaises(TypeError):
830 self._def.value = 'yes'
831
832 def test_assign_uint(self):
1eccc498
SM
833 uint_fc = self._tc.create_unsigned_integer_field_class(32)
834 field = _create_field(self._tc, uint_fc)
9cf643d1
PP
835 raw = 1777
836 field.value = 1777
837 self.assertEqual(field, raw)
9cf643d1 838
7bb4180f
FD
839 def test_assign_big_uint(self):
840 uint_fc = self._tc.create_unsigned_integer_field_class(64)
841 field = _create_field(self._tc, uint_fc)
842 # Larger than the IEEE 754 double-precision exact representation of
843 # integers.
844 raw = (2**53) + 1
845 field.value = (2**53) + 1
846 self.assertEqual(field, raw)
847
9cf643d1 848 def test_assign_uint_invalid_neg(self):
1eccc498
SM
849 uint_fc = self._tc.create_unsigned_integer_field_class(32)
850 field = _create_field(self._tc, uint_fc)
9cf643d1
PP
851
852 with self.assertRaises(ValueError):
853 field.value = -23
854
b0bdda42
JG
855 def test_str_op(self):
856 self.assertEqual(str(self._def), str(self._def_value))
857
9cf643d1
PP
858
859_inject_numeric_testing_methods(_TestIntegerFieldCommon)
860
861
1eccc498
SM
862class SignedIntegerFieldTestCase(_TestIntegerFieldCommon, unittest.TestCase):
863 def _create_fc(self, tc):
864 return tc.create_signed_integer_field_class(25)
865
9cf643d1 866 def setUp(self):
1eccc498
SM
867 self._tc = get_default_trace_class()
868 self._field = _create_field(self._tc, self._create_fc(self._tc))
869 self._field.value = 17
870 self._def = _create_field(self._tc, self._create_fc(self._tc))
9cf643d1
PP
871 self._def.value = 17
872 self._def_value = 17
873 self._def_new_value = -101
874
811644b8 875
1eccc498
SM
876class SignedEnumerationFieldTestCase(_TestIntegerFieldCommon, unittest.TestCase):
877 def _create_fc(self, tc):
878 fc = tc.create_signed_enumeration_field_class(32)
879 fc.map_range('something', 17)
880 fc.map_range('speaker', 12, 16)
881 fc.map_range('can', 18, 2540)
882 fc.map_range('whole range', -(2 ** 31), (2 ** 31) - 1)
883 fc.map_range('zip', -45, 1001)
884 return fc
9cf643d1 885
9cf643d1 886 def setUp(self):
1eccc498
SM
887 self._tc = get_default_trace_class()
888 self._field = _create_field(self._tc, self._create_fc(self._tc))
889 self._def = _create_field(self._tc, self._create_fc(self._tc))
9cf643d1
PP
890 self._def.value = 17
891 self._def_value = 17
892 self._def_new_value = -101
893
b0bdda42
JG
894 def test_str_op(self):
895 expected_string_found = False
896 s = str(self._def)
897
898 # Establish all permutations of the three expected matches since
899 # the order in which mappings are enumerated is not explicitly part of
900 # the API.
1eccc498
SM
901 for p in itertools.permutations(['whole range', 'something',
902 'zip']):
b0bdda42
JG
903 candidate = '{} ({})'.format(self._def_value, ', '.join(p))
904 if candidate == s:
905 expected_string_found = True
906 break
907
908 self.assertTrue(expected_string_found)
909
1eccc498
SM
910 def test_labels(self):
911 self._field.value = 17
912 labels = sorted(self._field.labels)
913 self.assertEqual(labels, ['something', 'whole range', 'zip'])
914
b0bdda42 915
1eccc498
SM
916class RealFieldTestCase(_TestNumericField, unittest.TestCase):
917 def _create_fc(self, tc):
918 return tc.create_real_field_class()
9cf643d1 919
9cf643d1 920 def setUp(self):
1eccc498
SM
921 self._tc = get_default_trace_class()
922 self._field = _create_field(self._tc, self._create_fc(self._tc))
923 self._def = _create_field(self._tc, self._create_fc(self._tc))
9cf643d1
PP
924 self._def.value = 52.7
925 self._def_value = 52.7
926 self._def_new_value = -17.164857
927
928 def _test_invalid_op(self, cb):
929 with self.assertRaises(TypeError):
930 cb()
931
932 def test_assign_true(self):
933 self._def.value = True
934 self.assertTrue(self._def)
9cf643d1
PP
935
936 def test_assign_false(self):
937 self._def.value = False
938 self.assertFalse(self._def)
9cf643d1
PP
939
940 def test_assign_pos_int(self):
941 raw = 477
942 self._def.value = raw
943 self.assertEqual(self._def, float(raw))
9cf643d1
PP
944
945 def test_assign_neg_int(self):
946 raw = -13
947 self._def.value = raw
948 self.assertEqual(self._def, float(raw))
9cf643d1
PP
949
950 def test_assign_int_field(self):
1eccc498
SM
951 int_fc = self._tc.create_signed_integer_field_class(32)
952 int_field = _create_field(self._tc, int_fc)
9cf643d1 953 raw = 999
1eccc498
SM
954 int_field.value = raw
955 self._def.value = int_field
9cf643d1 956 self.assertEqual(self._def, float(raw))
9cf643d1
PP
957
958 def test_assign_float(self):
959 raw = -19.23
960 self._def.value = raw
961 self.assertEqual(self._def, raw)
9cf643d1
PP
962
963 def test_assign_float_field(self):
1eccc498 964 field = _create_field(self._tc, self._create_fc(self._tc))
9cf643d1
PP
965 raw = 101.32
966 field.value = raw
967 self._def.value = field
968 self.assertEqual(self._def, raw)
9cf643d1
PP
969
970 def test_assign_invalid_type(self):
971 with self.assertRaises(TypeError):
972 self._def.value = 'yes'
973
974 def test_invalid_lshift(self):
975 self._test_invalid_op(lambda: self._def << 23)
976
977 def test_invalid_rshift(self):
978 self._test_invalid_op(lambda: self._def >> 23)
979
980 def test_invalid_and(self):
981 self._test_invalid_op(lambda: self._def & 23)
982
983 def test_invalid_or(self):
984 self._test_invalid_op(lambda: self._def | 23)
985
986 def test_invalid_xor(self):
987 self._test_invalid_op(lambda: self._def ^ 23)
988
989 def test_invalid_invert(self):
990 self._test_invalid_op(lambda: ~self._def)
991
b0bdda42
JG
992 def test_str_op(self):
993 self.assertEqual(str(self._def), str(self._def_value))
994
9cf643d1 995
1eccc498 996_inject_numeric_testing_methods(RealFieldTestCase)
9cf643d1
PP
997
998
1eccc498 999class StringFieldTestCase(unittest.TestCase):
9cf643d1 1000 def setUp(self):
1eccc498 1001 self._tc = get_default_trace_class()
9cf643d1 1002 self._def_value = 'Hello, World!'
1eccc498 1003 self._def = _create_string_field(self._tc)
9cf643d1
PP
1004 self._def.value = self._def_value
1005 self._def_new_value = 'Yes!'
1006
1007 def test_assign_int(self):
1008 with self.assertRaises(TypeError):
1009 self._def.value = 283
1010
9cf643d1 1011 def test_assign_string_field(self):
1eccc498 1012 field = _create_string_field(self._tc)
9cf643d1
PP
1013 raw = 'zorg'
1014 field.value = raw
1015 self.assertEqual(field, raw)
1016
1017 def test_eq(self):
1018 self.assertEqual(self._def, self._def_value)
1019
1eccc498 1020 def test_not_eq(self):
9cf643d1
PP
1021 self.assertNotEqual(self._def, 23)
1022
1023 def test_lt_vstring(self):
1eccc498 1024 s1 = _create_string_field(self._tc)
9cf643d1 1025 s1.value = 'allo'
1eccc498 1026 s2 = _create_string_field(self._tc)
9cf643d1
PP
1027 s2.value = 'bateau'
1028 self.assertLess(s1, s2)
1029
1030 def test_lt_string(self):
1eccc498 1031 s1 = _create_string_field(self._tc)
9cf643d1
PP
1032 s1.value = 'allo'
1033 self.assertLess(s1, 'bateau')
1034
1035 def test_le_vstring(self):
1eccc498 1036 s1 = _create_string_field(self._tc)
9cf643d1 1037 s1.value = 'allo'
1eccc498 1038 s2 = _create_string_field(self._tc)
9cf643d1
PP
1039 s2.value = 'bateau'
1040 self.assertLessEqual(s1, s2)
1041
1042 def test_le_string(self):
1eccc498 1043 s1 = _create_string_field(self._tc)
9cf643d1
PP
1044 s1.value = 'allo'
1045 self.assertLessEqual(s1, 'bateau')
1046
1047 def test_gt_vstring(self):
1eccc498 1048 s1 = _create_string_field(self._tc)
9cf643d1 1049 s1.value = 'allo'
1eccc498 1050 s2 = _create_string_field(self._tc)
9cf643d1
PP
1051 s2.value = 'bateau'
1052 self.assertGreater(s2, s1)
1053
1054 def test_gt_string(self):
1eccc498 1055 s1 = _create_string_field(self._tc)
9cf643d1
PP
1056 s1.value = 'allo'
1057 self.assertGreater('bateau', s1)
1058
1059 def test_ge_vstring(self):
1eccc498 1060 s1 = _create_string_field(self._tc)
9cf643d1 1061 s1.value = 'allo'
1eccc498 1062 s2 = _create_string_field(self._tc)
9cf643d1
PP
1063 s2.value = 'bateau'
1064 self.assertGreaterEqual(s2, s1)
1065
1066 def test_ge_string(self):
1eccc498 1067 s1 = _create_string_field(self._tc)
9cf643d1
PP
1068 s1.value = 'allo'
1069 self.assertGreaterEqual('bateau', s1)
1070
1071 def test_bool_op(self):
1072 self.assertEqual(bool(self._def), bool(self._def_value))
1073
1074 def test_str_op(self):
1075 self.assertEqual(str(self._def), str(self._def_value))
1076
1077 def test_len(self):
1078 self.assertEqual(len(self._def), len(self._def_value))
1079
1080 def test_getitem(self):
1081 self.assertEqual(self._def[5], self._def_value[5])
1082
1083 def test_append_str(self):
1084 to_append = 'meow meow meow'
1085 self._def += to_append
1086 self._def_value += to_append
1087 self.assertEqual(self._def, self._def_value)
1088
1089 def test_append_string_field(self):
1eccc498 1090 field = _create_string_field(self._tc)
9cf643d1
PP
1091 to_append = 'meow meow meow'
1092 field.value = to_append
1093 self._def += field
1094 self._def_value += to_append
1095 self.assertEqual(self._def, self._def_value)
1096
742e4747 1097
1eccc498 1098class _TestArrayFieldCommon:
9cf643d1
PP
1099 def _modify_def(self):
1100 self._def[2] = 23
1101
1102 def test_bool_op_true(self):
1103 self.assertTrue(self._def)
1104
1105 def test_len(self):
1106 self.assertEqual(len(self._def), 3)
1107
1eccc498
SM
1108 def test_length(self):
1109 self.assertEqual(self._def.length, 3)
1110
9cf643d1
PP
1111 def test_getitem(self):
1112 field = self._def[1]
1eccc498 1113 self.assertIs(type(field), bt2.field._SignedIntegerField)
9cf643d1
PP
1114 self.assertEqual(field, 1847)
1115
1116 def test_eq(self):
1eccc498 1117 field = _create_int_array_field(self._tc, 3)
9cf643d1
PP
1118 field[0] = 45
1119 field[1] = 1847
1120 field[2] = 1948754
1121 self.assertEqual(self._def, field)
1122
1123 def test_eq_invalid_type(self):
1124 self.assertNotEqual(self._def, 23)
1125
1126 def test_eq_diff_len(self):
1eccc498 1127 field = _create_int_array_field(self._tc, 2)
9cf643d1
PP
1128 field[0] = 45
1129 field[1] = 1847
1130 self.assertNotEqual(self._def, field)
1131
1132 def test_eq_diff_content_same_len(self):
1eccc498 1133 field = _create_int_array_field(self._tc, 3)
9cf643d1
PP
1134 field[0] = 45
1135 field[1] = 1846
1136 field[2] = 1948754
1137 self.assertNotEqual(self._def, field)
1138
1139 def test_setitem(self):
1140 self._def[2] = 24
1141 self.assertEqual(self._def[2], 24)
1142
1143 def test_setitem_int_field(self):
1eccc498
SM
1144 int_fc = self._tc.create_signed_integer_field_class(32)
1145 int_field = _create_field(self._tc, int_fc)
9cf643d1
PP
1146 int_field.value = 19487
1147 self._def[1] = int_field
1148 self.assertEqual(self._def[1], 19487)
1149
1150 def test_setitem_non_basic_field(self):
1eccc498 1151 array_field = _create_struct_array_field(self._tc, 2)
9cf643d1
PP
1152 with self.assertRaises(TypeError):
1153 array_field[1] = 23
1154
1155 def test_setitem_none(self):
1156 with self.assertRaises(TypeError):
1157 self._def[1] = None
1158
1159 def test_setitem_index_wrong_type(self):
1160 with self.assertRaises(TypeError):
1161 self._def['yes'] = 23
1162
1163 def test_setitem_index_neg(self):
1164 with self.assertRaises(IndexError):
1165 self._def[-2] = 23
1166
1167 def test_setitem_index_out_of_range(self):
1168 with self.assertRaises(IndexError):
1169 self._def[len(self._def)] = 134679
1170
1171 def test_iter(self):
1172 for field, value in zip(self._def, (45, 1847, 1948754)):
1173 self.assertEqual(field, value)
1174
7c54e2e7
JG
1175 def test_value_int_field(self):
1176 values = [45646, 145, 12145]
1177 self._def.value = values
1178 self.assertEqual(values, self._def)
1179
7c54e2e7
JG
1180 def test_value_check_sequence(self):
1181 values = 42
1182 with self.assertRaises(TypeError):
1183 self._def.value = values
1184
1185 def test_value_wrong_type_in_sequence(self):
1186 values = [32, 'hello', 11]
1187 with self.assertRaises(TypeError):
1188 self._def.value = values
1189
1190 def test_value_complex_type(self):
1eccc498
SM
1191 struct_fc = self._tc.create_structure_field_class()
1192 int_fc = self._tc.create_signed_integer_field_class(32)
1193 another_int_fc = self._tc.create_signed_integer_field_class(32)
1194 str_fc = self._tc.create_string_field_class()
1195 struct_fc.append_member(field_class=int_fc, name='an_int')
1196 struct_fc.append_member(field_class=str_fc, name='a_string')
1197 struct_fc.append_member(field_class=another_int_fc, name='another_int')
1198 array_fc = self._tc.create_static_array_field_class(struct_fc, 3)
1199 stream = _create_stream(self._tc, [('array_field', array_fc)])
7c54e2e7
JG
1200 values = [
1201 {
1202 'an_int': 42,
1203 'a_string': 'hello',
1204 'another_int': 66
1205 },
1206 {
1207 'an_int': 1,
1208 'a_string': 'goodbye',
1209 'another_int': 488
1210 },
1211 {
1212 'an_int': 156,
1213 'a_string': 'or not',
1214 'another_int': 4648
1215 },
1216 ]
1217
1eccc498 1218 array = stream.create_packet().context_field['array_field']
7c54e2e7
JG
1219 array.value = values
1220 self.assertEqual(values, array)
1221 values[0]['an_int'] = 'a string'
1222 with self.assertRaises(TypeError):
1223 array.value = values
9cf643d1 1224
b0bdda42
JG
1225 def test_str_op(self):
1226 s = str(self._def)
1227 expected_string = '[{}]'.format(', '.join(
1228 [repr(v) for v in self._def_value]))
1229 self.assertEqual(expected_string, s)
1230
742e4747 1231
1eccc498 1232class StaticArrayFieldTestCase(_TestArrayFieldCommon, unittest.TestCase):
9cf643d1 1233 def setUp(self):
1eccc498
SM
1234 self._tc = get_default_trace_class()
1235 self._def = _create_int_array_field(self._tc, 3)
9cf643d1
PP
1236 self._def[0] = 45
1237 self._def[1] = 1847
1238 self._def[2] = 1948754
7c54e2e7 1239 self._def_value = [45, 1847, 1948754]
9cf643d1 1240
7c54e2e7
JG
1241 def test_value_wrong_len(self):
1242 values = [45, 1847]
1243 with self.assertRaises(ValueError):
1244 self._def.value = values
1245
9cf643d1 1246
1eccc498 1247class DynamicArrayFieldTestCase(_TestArrayFieldCommon, unittest.TestCase):
9cf643d1 1248 def setUp(self):
1eccc498
SM
1249 self._tc = get_default_trace_class()
1250 self._def = _create_dynamic_array(self._tc)
9cf643d1
PP
1251 self._def[0] = 45
1252 self._def[1] = 1847
1253 self._def[2] = 1948754
7c54e2e7 1254 self._def_value = [45, 1847, 1948754]
9cf643d1 1255
7c54e2e7
JG
1256 def test_value_resize(self):
1257 new_values = [1, 2, 3, 4]
1258 self._def.value = new_values
1259 self.assertCountEqual(self._def, new_values)
1260
1eccc498
SM
1261 def test_set_length(self):
1262 self._def.length = 4
1263 self._def[3] = 0
1264 self.assertEqual(len(self._def), 4)
7c54e2e7 1265
1eccc498 1266 def test_set_invalid_length(self):
7c54e2e7 1267 with self.assertRaises(TypeError):
1eccc498
SM
1268 self._def.length = 'cheval'
1269
1270
1271class StructureFieldTestCase(unittest.TestCase):
1272 def _create_fc(self, tc):
1273 fc = tc.create_structure_field_class()
1274 fc.append_member('A', self._fc0_fn())
1275 fc.append_member('B', self._fc1_fn())
1276 fc.append_member('C', self._fc2_fn())
1277 fc.append_member('D', self._fc3_fn())
1278 fc.append_member('E', self._fc4_fn())
1279 fc5 = self._fc5_fn()
1280 fc5.append_member('F_1', self._fc5_inner_fn())
1281 fc.append_member('F', fc5)
1282 return fc
7c54e2e7 1283
9cf643d1 1284 def setUp(self):
1eccc498
SM
1285 self._tc = get_default_trace_class()
1286 self._fc0_fn = self._tc.create_signed_integer_field_class
1287 self._fc1_fn = self._tc.create_string_field_class
1288 self._fc2_fn = self._tc.create_real_field_class
1289 self._fc3_fn = self._tc.create_signed_integer_field_class
1290 self._fc4_fn = self._tc.create_structure_field_class
1291 self._fc5_fn = self._tc.create_structure_field_class
1292 self._fc5_inner_fn = self._tc.create_signed_integer_field_class
1293
1294 self._fc = self._create_fc(self._tc)
1295 self._def = _create_field(self._tc, self._fc)
9cf643d1
PP
1296 self._def['A'] = -1872
1297 self._def['B'] = 'salut'
1298 self._def['C'] = 17.5
1299 self._def['D'] = 16497
1eccc498
SM
1300 self._def['E'] = {}
1301 self._def['F'] = {'F_1': 52}
b0bdda42
JG
1302 self._def_value = {
1303 'A': -1872,
1304 'B': 'salut',
1305 'C': 17.5,
1eccc498
SM
1306 'D': 16497,
1307 'E': {},
1308 'F': {'F_1': 52}
b0bdda42 1309 }
9cf643d1
PP
1310
1311 def _modify_def(self):
1312 self._def['B'] = 'hola'
1313
1314 def test_bool_op_true(self):
1315 self.assertTrue(self._def)
1316
1317 def test_bool_op_false(self):
1eccc498 1318 field = self._def['E']
9cf643d1
PP
1319 self.assertFalse(field)
1320
1321 def test_len(self):
1eccc498 1322 self.assertEqual(len(self._def), len(self._def_value))
9cf643d1
PP
1323
1324 def test_getitem(self):
1325 field = self._def['A']
1eccc498 1326 self.assertIs(type(field), bt2.field._SignedIntegerField)
9cf643d1
PP
1327 self.assertEqual(field, -1872)
1328
1eccc498 1329 def test_member_at_index_out_of_bounds_after(self):
811644b8 1330 with self.assertRaises(IndexError):
1eccc498 1331 self._def.member_at_index(len(self._def_value))
811644b8 1332
9cf643d1 1333 def test_eq(self):
1eccc498 1334 field = _create_field(self._tc, self._create_fc(self._tc, ))
9cf643d1
PP
1335 field['A'] = -1872
1336 field['B'] = 'salut'
1337 field['C'] = 17.5
1338 field['D'] = 16497
1eccc498
SM
1339 field['E'] = {}
1340 field['F'] = {'F_1': 52}
9cf643d1
PP
1341 self.assertEqual(self._def, field)
1342
1343 def test_eq_invalid_type(self):
1344 self.assertNotEqual(self._def, 23)
1345
1346 def test_eq_diff_len(self):
1eccc498
SM
1347 fc = self._tc.create_structure_field_class()
1348 fc.append_member('A', self._fc0_fn())
1349 fc.append_member('B', self._fc1_fn())
1350 fc.append_member('C', self._fc2_fn())
1351
1352 field = _create_field(self._tc, fc)
9cf643d1
PP
1353 field['A'] = -1872
1354 field['B'] = 'salut'
1355 field['C'] = 17.5
1356 self.assertNotEqual(self._def, field)
1357
1eccc498
SM
1358 def test_eq_diff_keys(self):
1359 fc = self._tc.create_structure_field_class()
1360 fc.append_member('U', self._fc0_fn())
1361 fc.append_member('V', self._fc1_fn())
1362 fc.append_member('W', self._fc2_fn())
1363 fc.append_member('X', self._fc3_fn())
1364 fc.append_member('Y', self._fc4_fn())
1365 fc.append_member('Z', self._fc5_fn())
1366 field = _create_field(self._tc, fc)
1367 field['U'] = -1871
1368 field['V'] = "gerry"
1369 field['W'] = 18.19
1370 field['X'] = 16497
1371 field['Y'] = {}
1372 field['Z'] = {}
1373 self.assertNotEqual(self._def, field)
1374
9cf643d1 1375 def test_eq_diff_content_same_len(self):
1eccc498 1376 field = _create_field(self._tc, self._create_fc(self._tc))
9cf643d1
PP
1377 field['A'] = -1872
1378 field['B'] = 'salut'
1379 field['C'] = 17.4
1380 field['D'] = 16497
1eccc498
SM
1381 field['E'] = {}
1382 field['F'] = {'F_1': 0}
9cf643d1
PP
1383 self.assertNotEqual(self._def, field)
1384
1385 def test_eq_same_content_diff_keys(self):
1eccc498
SM
1386 fc = self._tc.create_structure_field_class()
1387 fc.append_member('A', self._fc0_fn())
1388 fc.append_member('B', self._fc1_fn())
1389 fc.append_member('E', self._fc2_fn())
1390 fc.append_member('D', self._fc3_fn())
1391 fc.append_member('C', self._fc4_fn())
1392 fc.append_member('F', self._fc5_fn())
1393 field = _create_field(self._tc, fc)
9cf643d1
PP
1394 field['A'] = -1872
1395 field['B'] = 'salut'
1eccc498 1396 field['E'] = 17.5
9cf643d1 1397 field['D'] = 16497
1eccc498
SM
1398 field['C'] = {}
1399 field['F'] = {}
9cf643d1
PP
1400 self.assertNotEqual(self._def, field)
1401
1402 def test_setitem(self):
1403 self._def['C'] = -18.47
1404 self.assertEqual(self._def['C'], -18.47)
1405
1406 def test_setitem_int_field(self):
1eccc498
SM
1407 int_fc = self._tc.create_signed_integer_field_class(32)
1408 int_field = _create_field(self._tc, int_fc)
9cf643d1
PP
1409 int_field.value = 19487
1410 self._def['D'] = int_field
1411 self.assertEqual(self._def['D'], 19487)
1412
1413 def test_setitem_non_basic_field(self):
1eccc498
SM
1414 elem_fc = self._tc.create_structure_field_class()
1415 struct_fc = self._tc.create_structure_field_class()
1416 struct_fc.append_member('A', elem_fc)
1417 struct_field = _create_field(self._tc, struct_fc)
9cf643d1 1418
236355c2
JG
1419 # Will fail on access to .items() of the value
1420 with self.assertRaises(AttributeError):
9cf643d1
PP
1421 struct_field['A'] = 23
1422
1423 def test_setitem_none(self):
1424 with self.assertRaises(TypeError):
1425 self._def['C'] = None
1426
1427 def test_setitem_key_wrong_type(self):
1428 with self.assertRaises(TypeError):
1429 self._def[3] = 23
1430
1431 def test_setitem_wrong_key(self):
1432 with self.assertRaises(KeyError):
1433 self._def['hi'] = 134679
1434
1eccc498
SM
1435 def test_member_at_index(self):
1436 self.assertEqual(self._def.member_at_index(1), 'salut')
9cf643d1
PP
1437
1438 def test_iter(self):
1439 orig_values = {
1440 'A': -1872,
1441 'B': 'salut',
1442 'C': 17.5,
1443 'D': 16497,
1eccc498
SM
1444 'E': {},
1445 'F': {'F_1': 52}
9cf643d1
PP
1446 }
1447
1448 for vkey, vval in self._def.items():
1449 val = orig_values[vkey]
1450 self.assertEqual(vval, val)
811644b8 1451
7c54e2e7
JG
1452 def test_value(self):
1453 orig_values = {
1454 'A': -1872,
1455 'B': 'salut',
1456 'C': 17.5,
1457 'D': 16497,
1eccc498
SM
1458 'E': {},
1459 'F': {'F_1': 52}
7c54e2e7
JG
1460 }
1461 self.assertEqual(self._def, orig_values)
1462
1463 def test_set_value(self):
1eccc498
SM
1464 int_fc = self._tc.create_signed_integer_field_class(32)
1465 another_int_fc = self._tc.create_signed_integer_field_class(32)
1466 str_fc = self._tc.create_string_field_class()
1467 struct_fc = self._tc.create_structure_field_class()
1468 struct_fc.append_member(field_class=int_fc, name='an_int')
1469 struct_fc.append_member(field_class=str_fc, name='a_string')
1470 struct_fc.append_member(field_class=another_int_fc, name='another_int')
7c54e2e7
JG
1471 values = {
1472 'an_int': 42,
1473 'a_string': 'hello',
1474 'another_int': 66
1475 }
1476
1eccc498 1477 struct = _create_field(self._tc, struct_fc)
7c54e2e7
JG
1478 struct.value = values
1479 self.assertEqual(values, struct)
1480
1481 bad_type_values = copy.deepcopy(values)
1482 bad_type_values['an_int'] = 'a string'
1483 with self.assertRaises(TypeError):
1484 struct.value = bad_type_values
1485
1486 unknown_key_values = copy.deepcopy(values)
1487 unknown_key_values['unknown_key'] = 16546
1488 with self.assertRaises(KeyError):
1489 struct.value = unknown_key_values
1490
b0bdda42
JG
1491 def test_str_op(self):
1492 expected_string_found = False
1493 s = str(self._def)
1494 # Establish all permutations of the three expected matches since
1495 # the order in which mappings are enumerated is not explicitly part of
1496 # the API.
1497 for p in itertools.permutations([(k, v) for k, v in self._def.items()]):
1498 items = ['{}: {}'.format(repr(k), repr(v)) for k, v in p]
1499 candidate = '{{{}}}'.format(', '.join(items))
1500 if candidate == s:
1501 expected_string_found = True
1502 break
1503
1504 self.assertTrue(expected_string_found)
1505
b0bdda42 1506
1eccc498
SM
1507class VariantFieldTestCase(unittest.TestCase):
1508 def _create_fc(self, tc):
1509 selector_fc = tc.create_signed_enumeration_field_class(field_value_range=32)
1510 selector_fc.map_range('corner', 23)
1511 selector_fc.map_range('zoom', 17, 20)
1512 selector_fc.map_range('mellotron', 1001)
1513 selector_fc.map_range('giorgio', 2000, 3000)
1514
1515 ft0 = tc.create_signed_integer_field_class(32)
1516 ft1 = tc.create_string_field_class()
1517 ft2 = tc.create_real_field_class()
1518 ft3 = tc.create_signed_integer_field_class(17)
1519
1520 fc = tc.create_variant_field_class()
1521 fc.append_option('corner', ft0)
1522 fc.append_option('zoom', ft1)
1523 fc.append_option('mellotron', ft2)
1524 fc.append_option('giorgio', ft3)
1525 fc.selector_field_class = selector_fc
1526
1527 top_fc = tc.create_structure_field_class()
1528 top_fc.append_member('selector_field', selector_fc)
1529 top_fc.append_member('variant_field', fc)
1530 return top_fc
811644b8 1531
811644b8 1532 def setUp(self):
1eccc498
SM
1533 self._tc = get_default_trace_class()
1534 fld = _create_field(self._tc, self._create_fc(self._tc))
1535 self._def = fld['variant_field']
811644b8 1536
1eccc498
SM
1537 def test_bool_op(self):
1538 self._def.selected_option_index = 2
1539 self._def.value = -17.34
1540 with self.assertRaises(NotImplementedError):
1541 bool(self._def)
811644b8 1542
1eccc498
SM
1543 def test_selected_option_index(self):
1544 self._def.selected_option_index = 2
1545 self.assertEqual(self._def.selected_option_index, 2)
811644b8 1546
1eccc498
SM
1547 def test_selected_option(self):
1548 self._def.selected_option_index = 2
1549 self._def.value = -17.34
1550 self.assertEqual(self._def.selected_option, -17.34)
1551
1552 self._def.selected_option_index = 3
1553 self._def.value = 1921
1554 self.assertEqual(self._def.selected_option, 1921)
811644b8
PP
1555
1556 def test_eq(self):
1eccc498
SM
1557 field = _create_field(self._tc, self._create_fc(self._tc))
1558 field = field['variant_field']
1559 field.selected_option_index = 0
1560 field.value = 1774
1561 self._def.selected_option_index = 0
1562 self._def.value = 1774
811644b8
PP
1563 self.assertEqual(self._def, field)
1564
1565 def test_eq_invalid_type(self):
1eccc498
SM
1566 self._def.selected_option_index = 1
1567 self._def.value = 'gerry'
811644b8 1568 self.assertNotEqual(self._def, 23)
742e4747 1569
b0bdda42 1570 def test_str_op_int(self):
1eccc498
SM
1571 field = _create_field(self._tc, self._create_fc(self._tc))
1572 field = field['variant_field']
1573 field.selected_option_index = 0
1574 field.value = 1774
1575 other_field = _create_field(self._tc, self._create_fc(self._tc))
1576 other_field = other_field['variant_field']
1577 other_field.selected_option_index = 0
1578 other_field.value = 1774
1579 self.assertEqual(str(field), str(other_field))
b0bdda42
JG
1580
1581 def test_str_op_str(self):
1eccc498
SM
1582 field = _create_field(self._tc, self._create_fc(self._tc))
1583 field = field['variant_field']
1584 field.selected_option_index = 1
1585 field.value = 'un beau grand bateau'
1586 other_field = _create_field(self._tc, self._create_fc(self._tc))
1587 other_field = other_field['variant_field']
1588 other_field.selected_option_index = 1
1589 other_field.value = 'un beau grand bateau'
1590 self.assertEqual(str(field), str(other_field))
1591
1592 def test_str_op_float(self):
1593 field = _create_field(self._tc, self._create_fc(self._tc))
1594 field = field['variant_field']
1595 field.selected_option_index = 2
1596 field.value = 14.4245
1597 other_field = _create_field(self._tc, self._create_fc(self._tc))
1598 other_field = other_field['variant_field']
1599 other_field.selected_option_index = 2
1600 other_field.value = 14.4245
1601 self.assertEqual(str(field), str(other_field))
This page took 0.105179 seconds and 4 git commands to generate.