xref: /aosp_15_r20/external/pigweed/pw_tokenizer/py/decode_test.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1#!/usr/bin/env python3
2# Copyright 2022 The Pigweed Authors
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may not
5# use this file except in compliance with the License. You may obtain a copy of
6# the License at
7#
8#     https://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations under
14# the License.
15"""Tests the tokenized string decode module."""
16
17from datetime import datetime
18import math
19import unittest
20
21import tokenized_string_decoding_test_data as tokenized_string
22import varint_test_data
23from pw_tokenizer import decode
24from pw_tokenizer import encode
25
26
27def error(msg, value=None) -> str:
28    """Formats msg as the message for an argument that failed to parse."""
29    if value is None:
30        return '<[{}]>'.format(msg)
31    return '<[{} ({})]>'.format(msg, value)
32
33
34class TestDecodeTokenized(unittest.TestCase):
35    """Tests decoding tokenized strings with various arguments."""
36
37    def test_decode_generated_data(self) -> None:
38        self.assertGreater(len(tokenized_string.TEST_DATA), 100)
39
40        for fmt, decoded, encoded in tokenized_string.TEST_DATA:
41            self.assertEqual(decode.decode(fmt, encoded, True), decoded)
42
43    def test_unicode_decode_errors(self) -> None:
44        """Tests unicode errors, which do not occur in the C++ decoding code."""
45        self.assertEqual(
46            decode.decode('Why, %c', b'\x01', True),
47            'Why, ' + error('%c ERROR', -1),
48        )
49
50        self.assertEqual(
51            decode.decode('%sXY%+ldxy%u', b'\x83N\x80!\x01\x02', True),
52            '{}XY{}xy{}'.format(
53                error('%s ERROR', "'N\\x80!'"),
54                error('%+ld SKIPPED', -1),
55                error('%u SKIPPED', 1),
56            ),
57        )
58
59        self.assertEqual(
60            decode.decode('%s%lld%9u', b'\x82$\x80\x80', True),
61            '{0}{1}{2}'.format(
62                error("%s ERROR ('$\\x80')"),
63                error('%lld SKIPPED'),
64                error('%9u SKIPPED'),
65            ),
66        )
67
68        self.assertEqual(
69            decode.decode('%c', b'\xff\xff\xff\xff\x0f', True),
70            error('%c ERROR', -2147483648),
71        )
72
73    def test_ignore_errors(self) -> None:
74        self.assertEqual(decode.decode('Why, %c', b'\x01'), 'Why, %c')
75
76        self.assertEqual(decode.decode('%s %d', b'\x01!'), '! %d')
77
78    def test_pointer(self) -> None:
79        """Tests pointer args, which are not natively supported in Python."""
80        self.assertEqual(
81            decode.decode('Hello: %p', b'\x00', True), 'Hello: 0x00000000'
82        )
83        self.assertEqual(
84            decode.decode('%p%d%d', b'\x02\x80', True),
85            '0x00000001<[%d ERROR]><[%d SKIPPED]>',
86        )
87
88    def test_nothing_printed_fails(self) -> None:
89        result = decode.FormatString('%n').format(b'')
90        self.assertFalse(result.ok())
91
92
93class TestPercentLiteralDecoding(unittest.TestCase):
94    """Tests decoding the %-literal in various invalid situations."""
95
96    def test_percent(self) -> None:
97        result = decode.FormatString('%%').format(b'')
98        self.assertTrue(result.ok())
99        self.assertEqual(result.value, '%')
100        self.assertEqual(result.remaining, b'')
101
102    def test_percent_with_leading_plus_fails(self) -> None:
103        result = decode.FormatString('%+%').format(b'')
104        self.assertFalse(result.ok())
105        self.assertEqual(result.remaining, b'')
106
107    def test_percent_with_leading_negative(self) -> None:
108        result = decode.FormatString('%-%').format(b'')
109        self.assertFalse(result.ok())
110        self.assertEqual(result.remaining, b'')
111
112    def test_percent_with_leading_space(self) -> None:
113        result = decode.FormatString('% %').format(b'')
114        self.assertFalse(result.ok())
115        self.assertEqual(result.remaining, b'')
116
117    def test_percent_with_leading_hashtag(self) -> None:
118        result = decode.FormatString('%#%').format(b'')
119        self.assertFalse(result.ok())
120        self.assertEqual(result.remaining, b'')
121
122    def test_percent_with_leading_zero(self) -> None:
123        result = decode.FormatString('%0%').format(b'')
124        self.assertFalse(result.ok())
125        self.assertEqual(result.remaining, b'')
126
127    def test_percent_with_length(self) -> None:
128        """Test that all length prefixes fail to decode with %."""
129
130        result = decode.FormatString('%hh%').format(b'')
131        self.assertFalse(result.ok())
132        self.assertEqual(result.remaining, b'')
133
134        result = decode.FormatString('%h%').format(b'')
135        self.assertFalse(result.ok())
136        self.assertEqual(result.remaining, b'')
137
138        result = decode.FormatString('%l%').format(b'')
139        self.assertFalse(result.ok())
140        self.assertEqual(result.remaining, b'')
141
142        result = decode.FormatString('%ll%').format(b'')
143        self.assertFalse(result.ok())
144        self.assertEqual(result.remaining, b'')
145
146        result = decode.FormatString('%L%').format(b'')
147        self.assertFalse(result.ok())
148        self.assertEqual(result.remaining, b'')
149
150        result = decode.FormatString('%j%').format(b'')
151        self.assertFalse(result.ok())
152        self.assertEqual(result.remaining, b'')
153
154        result = decode.FormatString('%z%').format(b'')
155        self.assertFalse(result.ok())
156        self.assertEqual(result.remaining, b'')
157
158        result = decode.FormatString('%t%').format(b'')
159        self.assertFalse(result.ok())
160        self.assertEqual(result.remaining, b'')
161
162    def test_percent_with_width(self):
163        result = decode.FormatString('%9%').format(b'')
164        self.assertFalse(result.ok())
165
166    def test_percent_with_multidigit_width(self):
167        result = decode.FormatString('%10%').format(b'')
168        self.assertFalse(result.ok())
169
170    def test_percent_with_star_width(self):
171        result = decode.FormatString('%*%').format(b'')
172        self.assertFalse(result.ok())
173
174    def test_percent_with_precision(self):
175        result = decode.FormatString('%.5%').format(b'')
176        self.assertFalse(result.ok())
177
178    def test_percent_with_multidigit_precision(self):
179        result = decode.FormatString('%.10%').format(b'')
180        self.assertFalse(result.ok())
181
182    def test_percent_with_star_precision(self):
183        result = decode.FormatString('%.*%').format(b'')
184        self.assertFalse(result.ok())
185
186
187# pylint: disable=too-many-public-methods
188class TestIntegerDecoding(unittest.TestCase):
189    """Tests decoding variable-length integers."""
190
191    def test_signed_integer_d(self) -> None:
192        result = decode.FormatString('%d').format(encode.encode_args(-10))
193        self.assertTrue(result.ok())
194        self.assertEqual(result.value, '-10')
195        self.assertEqual(result.remaining, b'')
196
197    def test_signed_integer_d_with_minus(self) -> None:
198        result = decode.FormatString('%-5d').format(encode.encode_args(10))
199        self.assertTrue(result.ok())
200        self.assertEqual(result.value, '10   ')
201        self.assertEqual(result.remaining, b'')
202
203    def test_signed_integer_d_with_plus(self) -> None:
204        result = decode.FormatString('%+d').format(encode.encode_args(10))
205        self.assertTrue(result.ok())
206        self.assertEqual(result.value, '+10')
207        self.assertEqual(result.remaining, b'')
208
209    def test_signed_integer_d_with_blank_space(self) -> None:
210        result = decode.FormatString('% d').format(encode.encode_args(10))
211        self.assertTrue(result.ok())
212        self.assertEqual(result.value, ' 10')
213        self.assertEqual(result.remaining, b'')
214
215    def test_signed_integer_d_with_plus_and_blank_space_ignores_blank_space(
216        self,
217    ) -> None:
218        result = decode.FormatString('%+ d').format(encode.encode_args(10))
219        self.assertTrue(result.ok())
220        self.assertEqual(result.value, '+10')
221        self.assertEqual(result.remaining, b'')
222
223        result = decode.FormatString('% +d').format(encode.encode_args(10))
224        self.assertTrue(result.ok())
225        self.assertEqual(result.value, '+10')
226        self.assertEqual(result.remaining, b'')
227
228    def test_signed_integer_d_with_hashtag(self) -> None:
229        result = decode.FormatString('%#d').format(encode.encode_args(10))
230        self.assertFalse(result.ok())
231
232    def test_signed_integer_d_with_zero(self) -> None:
233        result = decode.FormatString('%05d').format(encode.encode_args(10))
234        self.assertTrue(result.ok())
235        self.assertEqual(result.value, '00010')
236        self.assertEqual(result.remaining, b'')
237
238    def test_signed_integer_d_with_length(self) -> None:
239        """Tests that length modifiers do not affect signed integer decoding."""
240        result = decode.FormatString('%hhd').format(encode.encode_args(-10))
241        self.assertTrue(result.ok())
242        self.assertEqual(result.value, '-10')
243        self.assertEqual(result.remaining, b'')
244
245        result = decode.FormatString('%hd').format(encode.encode_args(-10))
246        self.assertTrue(result.ok())
247        self.assertEqual(result.value, '-10')
248        self.assertEqual(result.remaining, b'')
249
250        result = decode.FormatString('%ld').format(encode.encode_args(-10))
251        self.assertTrue(result.ok())
252        self.assertEqual(result.value, '-10')
253        self.assertEqual(result.remaining, b'')
254
255        result = decode.FormatString('%lld').format(encode.encode_args(-10))
256        self.assertTrue(result.ok())
257        self.assertEqual(result.value, '-10')
258        self.assertEqual(result.remaining, b'')
259
260        result = decode.FormatString('%jd').format(encode.encode_args(-10))
261        self.assertTrue(result.ok())
262        self.assertEqual(result.value, '-10')
263        self.assertEqual(result.remaining, b'')
264
265        result = decode.FormatString('%zd').format(encode.encode_args(-10))
266        self.assertTrue(result.ok())
267        self.assertEqual(result.value, '-10')
268        self.assertEqual(result.remaining, b'')
269
270        result = decode.FormatString('%td').format(encode.encode_args(-10))
271        self.assertTrue(result.ok())
272        self.assertEqual(result.value, '-10')
273        self.assertEqual(result.remaining, b'')
274
275    def test_signed_integer_d_with_width(self) -> None:
276        result = decode.FormatString('%5d').format(encode.encode_args(-10))
277        self.assertTrue(result.ok())
278        self.assertEqual(result.value, '  -10')
279        self.assertEqual(result.remaining, b'')
280
281    def test_signed_integer_d_with_width_and_0_flag(self) -> None:
282        result = decode.FormatString('%05d').format(encode.encode_args(-10))
283        self.assertTrue(result.ok())
284        self.assertEqual(result.value, '-0010')
285
286    def test_signed_integer_d_with_multidigit_width(self) -> None:
287        result = decode.FormatString('%10d').format(encode.encode_args(-10))
288        self.assertTrue(result.ok())
289        self.assertEqual(result.value, '       -10')
290
291    def test_signed_integer_d_with_star_width(self) -> None:
292        result = decode.FormatString('%*d').format(encode.encode_args(10, -10))
293        self.assertTrue(result.ok())
294        self.assertEqual(result.value, '       -10')
295
296    def test_signed_integer_d_with_missing_width_or_value(self) -> None:
297        result = decode.FormatString('%*d').format(encode.encode_args(-10))
298        self.assertFalse(result.ok())
299
300    def test_signed_integer_d_with_precision(self) -> None:
301        result = decode.FormatString('%.5d').format(encode.encode_args(-10))
302        self.assertTrue(result.ok())
303        self.assertEqual(result.value, '-00010')
304
305    def test_signed_integer_d_with_multidigit_precision(self) -> None:
306        result = decode.FormatString('%.10d').format(encode.encode_args(-10))
307        self.assertTrue(result.ok())
308        self.assertEqual(result.value, '-0000000010')
309
310    def test_signed_integer_d_with_star_precision(self) -> None:
311        result = decode.FormatString('%.*d').format(encode.encode_args(10, -10))
312        self.assertTrue(result.ok())
313        self.assertEqual(result.value, '-0000000010')
314
315    def test_signed_integer_d_with_zero_precision(self) -> None:
316        result = decode.FormatString('%.0d').format(encode.encode_args(-10))
317        self.assertTrue(result.ok())
318        self.assertEqual(result.value, '-10')
319
320    def test_signed_integer_d_with_empty_precision(self) -> None:
321        result = decode.FormatString('%.d').format(encode.encode_args(-10))
322        self.assertTrue(result.ok())
323        self.assertEqual(result.value, '-10')
324
325    def test_zero_with_zero_precision(self) -> None:
326        result = decode.FormatString('%.0d').format(encode.encode_args(0))
327        self.assertTrue(result.ok())
328        self.assertEqual(result.value, '')
329
330    def test_zero_with_empty_precision(self) -> None:
331        result = decode.FormatString('%.d').format(encode.encode_args(0))
332        self.assertTrue(result.ok())
333        self.assertEqual(result.value, '')
334
335    def test_signed_integer_d_with_width_and_precision(self) -> None:
336        result = decode.FormatString('%10.5d').format(encode.encode_args(-10))
337        self.assertTrue(result.ok())
338        self.assertEqual(result.value, '    -00010')
339
340    def test_signed_integer_d_with_star_width_and_precision(self) -> None:
341        result = decode.FormatString('%*.*d').format(
342            encode.encode_args(15, 10, -10)
343        )
344        self.assertTrue(result.ok())
345        self.assertEqual(result.value, '    -0000000010')
346
347    def test_signed_integer_d_with_missing_precision_or_value(self) -> None:
348        result = decode.FormatString('%.*d').format(encode.encode_args(-10))
349        self.assertFalse(result.ok())
350
351    def test_64_bit_specifier_workaround(self) -> None:
352        result = decode.FormatString('%.u%.*lu%0*lu').format(
353            encode.encode_args(0, 0, 0, 0, 0)
354        )
355        self.assertTrue(result.ok())
356        self.assertEqual(result.value, '0')
357        self.assertEqual(result.remaining, b'')
358
359        result = decode.FormatString('%.u%.*lu%0*lu').format(
360            encode.encode_args(0, 0, 1, 9, 0)
361        )
362        self.assertTrue(result.ok())
363        self.assertEqual(result.value, '1000000000')
364        self.assertEqual(result.remaining, b'')
365
366        result = decode.FormatString('%.u%.*lu%0*lu').format(
367            encode.encode_args(1, 9, 0, 9, 0)
368        )
369        self.assertTrue(result.ok())
370        self.assertEqual(result.value, '1000000000000000000')
371        self.assertEqual(result.remaining, b'')
372
373    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
374
375    def test_signed_integer_i(self) -> None:
376        result = decode.FormatString('%i').format(encode.encode_args(-10))
377        self.assertTrue(result.ok())
378        self.assertEqual(result.value, '-10')
379        self.assertEqual(result.remaining, b'')
380
381    def test_signed_integer_i_with_minus(self) -> None:
382        result = decode.FormatString('%-5i').format(encode.encode_args(10))
383        self.assertTrue(result.ok())
384        self.assertEqual(result.value, '10   ')
385        self.assertEqual(result.remaining, b'')
386
387    def test_signed_integer_i_with_plus(self) -> None:
388        result = decode.FormatString('%+i').format(encode.encode_args(10))
389        self.assertTrue(result.ok())
390        self.assertEqual(result.value, '+10')
391        self.assertEqual(result.remaining, b'')
392
393    def test_signed_integer_i_with_blank_space(self) -> None:
394        result = decode.FormatString('% i').format(encode.encode_args(10))
395        self.assertTrue(result.ok())
396        self.assertEqual(result.value, ' 10')
397        self.assertEqual(result.remaining, b'')
398
399    def test_signed_integer_i_with_plus_and_blank_space_ignores_blank_space(
400        self,
401    ) -> None:
402        result = decode.FormatString('%+ i').format(encode.encode_args(10))
403        self.assertTrue(result.ok())
404        self.assertEqual(result.value, '+10')
405        self.assertEqual(result.remaining, b'')
406
407        result = decode.FormatString('% +i').format(encode.encode_args(10))
408        self.assertTrue(result.ok())
409        self.assertEqual(result.value, '+10')
410        self.assertEqual(result.remaining, b'')
411
412    def test_signed_integer_i_with_hashtag(self) -> None:
413        result = decode.FormatString('%#i').format(encode.encode_args(10))
414        self.assertFalse(result.ok())
415        self.assertEqual(result.remaining, encode.encode_args(10))
416
417    def test_signed_integer_i_with_zero(self) -> None:
418        result = decode.FormatString('%05i').format(encode.encode_args(10))
419        self.assertTrue(result.ok())
420        self.assertEqual(result.value, '00010')
421        self.assertEqual(result.remaining, b'')
422
423    def test_signed_integer_i_with_length(self) -> None:
424        """Tests that length modifiers do not affect signed integer decoding."""
425        result = decode.FormatString('%hhi').format(encode.encode_args(-10))
426        self.assertTrue(result.ok())
427        self.assertEqual(result.value, '-10')
428        self.assertEqual(result.remaining, b'')
429
430        result = decode.FormatString('%hi').format(encode.encode_args(-10))
431        self.assertTrue(result.ok())
432        self.assertEqual(result.value, '-10')
433        self.assertEqual(result.remaining, b'')
434
435        result = decode.FormatString('%li').format(encode.encode_args(-10))
436        self.assertTrue(result.ok())
437        self.assertEqual(result.value, '-10')
438        self.assertEqual(result.remaining, b'')
439
440        result = decode.FormatString('%lli').format(encode.encode_args(-10))
441        self.assertTrue(result.ok())
442        self.assertEqual(result.value, '-10')
443        self.assertEqual(result.remaining, b'')
444
445        result = decode.FormatString('%ji').format(encode.encode_args(-10))
446        self.assertTrue(result.ok())
447        self.assertEqual(result.value, '-10')
448        self.assertEqual(result.remaining, b'')
449
450        result = decode.FormatString('%zi').format(encode.encode_args(-10))
451        self.assertTrue(result.ok())
452        self.assertEqual(result.value, '-10')
453        self.assertEqual(result.remaining, b'')
454
455        result = decode.FormatString('%ti').format(encode.encode_args(-10))
456        self.assertTrue(result.ok())
457        self.assertEqual(result.value, '-10')
458        self.assertEqual(result.remaining, b'')
459
460    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
461
462    def test_unsigned_integer(self) -> None:
463        result = decode.FormatString('%u').format(encode.encode_args(10))
464        self.assertTrue(result.ok())
465        self.assertEqual(result.value, '10')
466        self.assertEqual(result.remaining, b'')
467
468    def test_unsigned_integer_with_hashtag(self) -> None:
469        result = decode.FormatString('%#u').format(encode.encode_args(10))
470        self.assertFalse(result.ok())
471
472    def test_unsigned_integer_with_length(self) -> None:
473        """Tests that length modifiers pass unsigned integer decoding."""
474        result = decode.FormatString('%hhu').format(encode.encode_args(10))
475        self.assertTrue(result.ok())
476        self.assertEqual(result.value, '10')
477        self.assertEqual(result.remaining, b'')
478
479        result = decode.FormatString('%hu').format(encode.encode_args(10))
480        self.assertTrue(result.ok())
481        self.assertEqual(result.value, '10')
482        self.assertEqual(result.remaining, b'')
483
484        result = decode.FormatString('%lu').format(encode.encode_args(10))
485        self.assertTrue(result.ok())
486        self.assertEqual(result.value, '10')
487        self.assertEqual(result.remaining, b'')
488
489        result = decode.FormatString('%llu').format(encode.encode_args(10))
490        self.assertTrue(result.ok())
491        self.assertEqual(result.value, '10')
492        self.assertEqual(result.remaining, b'')
493
494        result = decode.FormatString('%ju').format(encode.encode_args(10))
495        self.assertTrue(result.ok())
496        self.assertEqual(result.value, '10')
497        self.assertEqual(result.remaining, b'')
498
499        result = decode.FormatString('%zu').format(encode.encode_args(10))
500        self.assertTrue(result.ok())
501        self.assertEqual(result.value, '10')
502        self.assertEqual(result.remaining, b'')
503
504        result = decode.FormatString('%tu').format(encode.encode_args(10))
505        self.assertTrue(result.ok())
506        self.assertEqual(result.value, '10')
507        self.assertEqual(result.remaining, b'')
508
509        result = decode.FormatString('%Lu').format(encode.encode_args(10))
510        self.assertTrue(result.ok())
511        self.assertEqual(result.value, '10')
512        self.assertEqual(result.remaining, b'')
513
514    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
515
516    def test_octal_integer(self) -> None:
517        result = decode.FormatString('%o').format(encode.encode_args(10))
518        self.assertTrue(result.ok())
519        self.assertEqual(result.value, '12')
520        self.assertEqual(result.remaining, b'')
521
522    def test_octal_integer_with_hashtag(self) -> None:
523        result = decode.FormatString('%#o').format(encode.encode_args(10))
524        self.assertTrue(result.ok())
525        self.assertEqual(result.value, '012')
526        self.assertEqual(result.remaining, b'')
527
528    def test_octal_integer_with_hashtag_and_width(self) -> None:
529        result = decode.FormatString('%#10o').format(encode.encode_args(10))
530        self.assertTrue(result.ok())
531        self.assertEqual(result.value, '       012')
532        self.assertEqual(result.remaining, b'')
533
534    def test_octal_integer_with_hashtag_and_zero_and_width(self) -> None:
535        result = decode.FormatString('%#010o').format(encode.encode_args(10))
536        self.assertTrue(result.ok())
537        self.assertEqual(result.value, '0000000012')
538        self.assertEqual(result.remaining, b'')
539
540    def test_octal_integer_with_minus_and_hashtag(self) -> None:
541        result = decode.FormatString('%#-5o').format(encode.encode_args(10))
542        self.assertTrue(result.ok())
543        self.assertEqual(result.value, '012  ')
544        self.assertEqual(result.remaining, b'')
545
546    def test_octal_integer_with_plus_and_hashtag(self) -> None:
547        result = decode.FormatString('%+#o').format(encode.encode_args(10))
548        self.assertTrue(result.ok())
549        self.assertEqual(result.value, '+012')
550        self.assertEqual(result.remaining, b'')
551
552    def test_octal_integer_with_space_and_hashtag(self) -> None:
553        result = decode.FormatString('% #o').format(encode.encode_args(10))
554        self.assertTrue(result.ok())
555        self.assertEqual(result.value, ' 012')
556        self.assertEqual(result.remaining, b'')
557
558    def test_octal_integer_with_zero_and_hashtag(self) -> None:
559        result = decode.FormatString('%#05o').format(encode.encode_args(10))
560        self.assertTrue(result.ok())
561        self.assertEqual(result.value, '00012')
562        self.assertEqual(result.remaining, b'')
563
564    def test_octal_integer_with_plus_and_space_and_hashtag_ignores_space(
565        self,
566    ) -> None:
567        result = decode.FormatString('%+ #o').format(encode.encode_args(10))
568        self.assertTrue(result.ok())
569        self.assertEqual(result.value, '+012')
570        self.assertEqual(result.remaining, b'')
571
572    def test_octal_integer_with_length(self) -> None:
573        """Tests that length modifiers do not affect octal integer decoding."""
574        result = decode.FormatString('%hho').format(encode.encode_args(10))
575        self.assertTrue(result.ok())
576        self.assertEqual(result.value, '12')
577        self.assertEqual(result.remaining, b'')
578
579        result = decode.FormatString('%ho').format(encode.encode_args(10))
580        self.assertTrue(result.ok())
581        self.assertEqual(result.value, '12')
582        self.assertEqual(result.remaining, b'')
583
584        result = decode.FormatString('%lo').format(encode.encode_args(10))
585        self.assertTrue(result.ok())
586        self.assertEqual(result.value, '12')
587        self.assertEqual(result.remaining, b'')
588
589        result = decode.FormatString('%llo').format(encode.encode_args(10))
590        self.assertTrue(result.ok())
591        self.assertEqual(result.value, '12')
592        self.assertEqual(result.remaining, b'')
593
594        result = decode.FormatString('%jo').format(encode.encode_args(10))
595        self.assertTrue(result.ok())
596        self.assertEqual(result.value, '12')
597        self.assertEqual(result.remaining, b'')
598
599        result = decode.FormatString('%zo').format(encode.encode_args(10))
600        self.assertTrue(result.ok())
601        self.assertEqual(result.value, '12')
602        self.assertEqual(result.remaining, b'')
603
604        result = decode.FormatString('%to').format(encode.encode_args(10))
605        self.assertTrue(result.ok())
606        self.assertEqual(result.value, '12')
607        self.assertEqual(result.remaining, b'')
608
609        result = decode.FormatString('%Lo').format(encode.encode_args(10))
610        self.assertTrue(result.ok())
611        self.assertEqual(result.value, '12')
612        self.assertEqual(result.remaining, b'')
613
614    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
615
616    def test_lowercase_hex_integer(self) -> None:
617        result = decode.FormatString('%x').format(encode.encode_args(10))
618        self.assertTrue(result.ok())
619        self.assertEqual(result.value, 'a')
620        self.assertEqual(result.remaining, b'')
621
622    def test_lowercase_hex_integer_with_hashtag(self) -> None:
623        result = decode.FormatString('%#x').format(encode.encode_args(10))
624        self.assertTrue(result.ok())
625        self.assertEqual(result.value, '0xa')
626        self.assertEqual(result.remaining, b'')
627
628    def test_lowercase_hex_integer_with_length(self) -> None:
629        """Tests that length modifiers do not affect lowercase hex decoding."""
630        result = decode.FormatString('%hhx').format(encode.encode_args(10))
631        self.assertTrue(result.ok())
632        self.assertEqual(result.value, 'a')
633        self.assertEqual(result.remaining, b'')
634
635        result = decode.FormatString('%hx').format(encode.encode_args(10))
636        self.assertTrue(result.ok())
637        self.assertEqual(result.value, 'a')
638        self.assertEqual(result.remaining, b'')
639
640        result = decode.FormatString('%lx').format(encode.encode_args(10))
641        self.assertTrue(result.ok())
642        self.assertEqual(result.value, 'a')
643        self.assertEqual(result.remaining, b'')
644
645        result = decode.FormatString('%llx').format(encode.encode_args(10))
646        self.assertTrue(result.ok())
647        self.assertEqual(result.value, 'a')
648        self.assertEqual(result.remaining, b'')
649
650        result = decode.FormatString('%jx').format(encode.encode_args(10))
651        self.assertTrue(result.ok())
652        self.assertEqual(result.value, 'a')
653        self.assertEqual(result.remaining, b'')
654
655        result = decode.FormatString('%zx').format(encode.encode_args(10))
656        self.assertTrue(result.ok())
657        self.assertEqual(result.value, 'a')
658        self.assertEqual(result.remaining, b'')
659
660        result = decode.FormatString('%tx').format(encode.encode_args(10))
661        self.assertTrue(result.ok())
662        self.assertEqual(result.value, 'a')
663        self.assertEqual(result.remaining, b'')
664
665        result = decode.FormatString('%Lx').format(encode.encode_args(10))
666        self.assertTrue(result.ok())
667        self.assertEqual(result.value, 'a')
668        self.assertEqual(result.remaining, b'')
669
670    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
671
672    def test_uppercase_hex_integer(self) -> None:
673        result = decode.FormatString('%X').format(encode.encode_args(10))
674        self.assertTrue(result.ok())
675        self.assertEqual(result.value, 'A')
676        self.assertEqual(result.remaining, b'')
677
678    def test_uppercase_hex_integer_with_hashtag(self) -> None:
679        result = decode.FormatString('%#X').format(encode.encode_args(10))
680        self.assertTrue(result.ok())
681        self.assertEqual(result.value, '0XA')
682        self.assertEqual(result.remaining, b'')
683
684    def test_uppercase_hex_integer_with_length(self) -> None:
685        """Tests that length modifiers do not affect uppercase hex decoding."""
686        result = decode.FormatString('%hhX').format(encode.encode_args(10))
687        self.assertTrue(result.ok())
688        self.assertEqual(result.value, 'A')
689        self.assertEqual(result.remaining, b'')
690
691        result = decode.FormatString('%hX').format(encode.encode_args(10))
692        self.assertTrue(result.ok())
693        self.assertEqual(result.value, 'A')
694        self.assertEqual(result.remaining, b'')
695
696        result = decode.FormatString('%lX').format(encode.encode_args(10))
697        self.assertTrue(result.ok())
698        self.assertEqual(result.value, 'A')
699        self.assertEqual(result.remaining, b'')
700
701        result = decode.FormatString('%llX').format(encode.encode_args(10))
702        self.assertTrue(result.ok())
703        self.assertEqual(result.value, 'A')
704        self.assertEqual(result.remaining, b'')
705
706        result = decode.FormatString('%jX').format(encode.encode_args(10))
707        self.assertTrue(result.ok())
708        self.assertEqual(result.value, 'A')
709        self.assertEqual(result.remaining, b'')
710
711        result = decode.FormatString('%zX').format(encode.encode_args(10))
712        self.assertTrue(result.ok())
713        self.assertEqual(result.value, 'A')
714        self.assertEqual(result.remaining, b'')
715
716        result = decode.FormatString('%tX').format(encode.encode_args(10))
717        self.assertTrue(result.ok())
718        self.assertEqual(result.value, 'A')
719        self.assertEqual(result.remaining, b'')
720
721        result = decode.FormatString('%LX').format(encode.encode_args(10))
722        self.assertTrue(result.ok())
723        self.assertEqual(result.value, 'A')
724        self.assertEqual(result.remaining, b'')
725
726    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
727
728    def test_decode_generated_data(self) -> None:
729        test_data = varint_test_data.TEST_DATA
730        self.assertGreater(len(test_data), 100)
731
732        for signed_spec, signed, unsigned_spec, unsigned, encoded in test_data:
733            self.assertEqual(
734                int(signed),
735                decode.FormatSpec.from_string(signed_spec)
736                .decode(bytearray(encoded))
737                .value,
738            )
739
740            self.assertEqual(
741                int(unsigned),
742                decode.FormatSpec.from_string(unsigned_spec)
743                .decode(bytearray(encoded))
744                .value,
745            )
746
747
748# pylint: disable=too-many-public-methods
749class TestFloatDecoding(unittest.TestCase):
750    """Tests decoding floating-point values using f or F."""
751
752    def test_lowercase_float(self) -> None:
753        result = decode.FormatString('%f').format(encode.encode_args(2.2))
754        self.assertTrue(result.ok())
755        self.assertEqual(result.value, '2.200000')
756        self.assertEqual(result.remaining, b'')
757
758    def test_lowercase_float_with_minus(self) -> None:
759        result = decode.FormatString('%-10f').format(encode.encode_args(2.2))
760        self.assertTrue(result.ok())
761        self.assertEqual(result.value, '2.200000  ')
762        self.assertEqual(result.remaining, b'')
763
764    def test_lowercase_float_with_plus(self) -> None:
765        result = decode.FormatString('%+f').format(encode.encode_args(2.2))
766        self.assertTrue(result.ok())
767        self.assertEqual(result.value, '+2.200000')
768        self.assertEqual(result.remaining, b'')
769
770    def test_lowercase_float_with_blank_space(self) -> None:
771        result = decode.FormatString('% f').format(encode.encode_args(2.2))
772        self.assertTrue(result.ok())
773        self.assertEqual(result.value, ' 2.200000')
774        self.assertEqual(result.remaining, b'')
775
776    def test_lowercase_float_with_plus_and_blank_space_ignores_blank_space(
777        self,
778    ) -> None:
779        result = decode.FormatString('%+ f').format(encode.encode_args(2.2))
780        self.assertTrue(result.ok())
781        self.assertEqual(result.value, '+2.200000')
782        self.assertEqual(result.remaining, b'')
783
784        result = decode.FormatString('% +f').format(encode.encode_args(2.2))
785        self.assertTrue(result.ok())
786        self.assertEqual(result.value, '+2.200000')
787        self.assertEqual(result.remaining, b'')
788
789    def test_lowercase_float_with_hashtag(self) -> None:
790        result = decode.FormatString('%.0f').format(encode.encode_args(2.0))
791        self.assertTrue(result.ok())
792        self.assertEqual(result.value, '2')
793        self.assertEqual(result.remaining, b'')
794
795        result = decode.FormatString('%#.0f').format(encode.encode_args(2.0))
796        self.assertTrue(result.ok())
797        self.assertEqual(result.value, '2.')
798        self.assertEqual(result.remaining, b'')
799
800    def test_lowercase_float_with_zero(self) -> None:
801        result = decode.FormatString('%010f').format(encode.encode_args(2.2))
802        self.assertTrue(result.ok())
803        self.assertEqual(result.value, '002.200000')
804        self.assertEqual(result.remaining, b'')
805
806    def test_lowercase_float_with_length(self) -> None:
807        """Tests that length modifiers do not affect f decoding."""
808        result = decode.FormatString('%hhf').format(encode.encode_args(2.2))
809        self.assertTrue(result.ok())
810        self.assertEqual(result.value, '2.200000')
811        self.assertEqual(result.remaining, b'')
812
813        result = decode.FormatString('%hf').format(encode.encode_args(2.2))
814        self.assertTrue(result.ok())
815        self.assertEqual(result.value, '2.200000')
816        self.assertEqual(result.remaining, b'')
817
818        result = decode.FormatString('%lf').format(encode.encode_args(2.2))
819        self.assertTrue(result.ok())
820        self.assertEqual(result.value, '2.200000')
821        self.assertEqual(result.remaining, b'')
822
823        result = decode.FormatString('%llf').format(encode.encode_args(2.2))
824        self.assertTrue(result.ok())
825        self.assertEqual(result.value, '2.200000')
826        self.assertEqual(result.remaining, b'')
827
828        result = decode.FormatString('%jf').format(encode.encode_args(2.2))
829        self.assertTrue(result.ok())
830        self.assertEqual(result.value, '2.200000')
831        self.assertEqual(result.remaining, b'')
832
833        result = decode.FormatString('%zf').format(encode.encode_args(2.2))
834        self.assertTrue(result.ok())
835        self.assertEqual(result.value, '2.200000')
836        self.assertEqual(result.remaining, b'')
837
838        result = decode.FormatString('%tf').format(encode.encode_args(2.2))
839        self.assertTrue(result.ok())
840        self.assertEqual(result.value, '2.200000')
841        self.assertEqual(result.remaining, b'')
842
843        result = decode.FormatString('%Lf').format(encode.encode_args(2.2))
844        self.assertTrue(result.ok())
845        self.assertEqual(result.value, '2.200000')
846        self.assertEqual(result.remaining, b'')
847
848    def test_lowercase_float_with_width(self) -> None:
849        result = decode.FormatString('%9f').format(encode.encode_args(2.2))
850        self.assertTrue(result.ok())
851        self.assertEqual(result.value, ' 2.200000')
852
853    def test_lowercase_float_with_multidigit_width(self) -> None:
854        result = decode.FormatString('%10f').format(encode.encode_args(2.2))
855        self.assertTrue(result.ok())
856        self.assertEqual(result.value, '  2.200000')
857
858    def test_lowercase_float_with_star_width(self) -> None:
859        result = decode.FormatString('%*f').format(encode.encode_args(10, 2.2))
860        self.assertTrue(result.ok())
861        self.assertEqual(result.value, '  2.200000')
862
863    def test_lowercase_float_non_number(self) -> None:
864        result = decode.FormatString('%f').format(encode.encode_args(math.inf))
865        self.assertTrue(result.ok())
866        self.assertEqual(result.value, 'inf')
867        self.assertEqual(result.remaining, b'')
868
869    def test_lowercase_float_with_precision(self) -> None:
870        result = decode.FormatString('%.4f').format(encode.encode_args(2.2))
871        self.assertTrue(result.ok())
872        self.assertEqual(result.value, '2.2000')
873
874    def test_lowercase_float_with_multidigit_precision(self) -> None:
875        result = decode.FormatString('%.10f').format(encode.encode_args(2.2))
876        self.assertTrue(result.ok())
877        self.assertEqual(result.value, '2.2000000477')
878
879    def test_lowercase_float_with_star_preision(self) -> None:
880        result = decode.FormatString('%.*f').format(encode.encode_args(10, 2.2))
881        self.assertTrue(result.ok())
882        self.assertEqual(result.value, '2.2000000477')
883
884    def test_lowercase_float_with_zero_precision(self) -> None:
885        result = decode.FormatString('%.0f').format(encode.encode_args(2.2))
886        self.assertTrue(result.ok())
887        self.assertEqual(result.value, '2')
888
889    def test_lowercase_float_with_empty_precision(self) -> None:
890        result = decode.FormatString('%.f').format(encode.encode_args(2.2))
891        self.assertTrue(result.ok())
892        self.assertEqual(result.value, '2')
893
894    def test_lowercase_float_with_width_and_precision(self) -> None:
895        result = decode.FormatString('%10.0f').format(encode.encode_args(2.2))
896        self.assertTrue(result.ok())
897        self.assertEqual(result.value, '         2')
898
899    def test_lowercase_float_with_star_width_and_star_precision(self) -> None:
900        result = decode.FormatString('%*.*f').format(
901            encode.encode_args(20, 10, 2.2)
902        )
903        self.assertTrue(result.ok())
904        self.assertEqual(result.value, '        2.2000000477')
905
906    def test_lowercase_float_non_number_with_minus(self) -> None:
907        result = decode.FormatString('%-5f').format(
908            encode.encode_args(math.inf)
909        )
910        self.assertTrue(result.ok())
911        self.assertEqual(result.value, 'inf  ')
912        self.assertEqual(result.remaining, b'')
913
914    def test_lowercase_float_non_number_with_plus(self) -> None:
915        result = decode.FormatString('%+f').format(encode.encode_args(math.inf))
916        self.assertTrue(result.ok())
917        self.assertEqual(result.value, '+inf')
918        self.assertEqual(result.remaining, b'')
919
920    def test_lowercase_float_non_number_with_blank_space(self) -> None:
921        result = decode.FormatString('% f').format(encode.encode_args(math.inf))
922        self.assertTrue(result.ok())
923        self.assertEqual(result.value, ' inf')
924        self.assertEqual(result.remaining, b'')
925
926    def test_lowercase_float_non_number_with_plus_and_blank_ignores_blank(
927        self,
928    ) -> None:
929        result = decode.FormatString('%+ f').format(
930            encode.encode_args(math.inf)
931        )
932        self.assertTrue(result.ok())
933        self.assertEqual(result.value, '+inf')
934        self.assertEqual(result.remaining, b'')
935
936        result = decode.FormatString('% +f').format(
937            encode.encode_args(math.inf)
938        )
939        self.assertTrue(result.ok())
940        self.assertEqual(result.value, '+inf')
941        self.assertEqual(result.remaining, b'')
942
943    def test_lowercase_float_non_number_with_hashtag(self) -> None:
944        result = decode.FormatString('%#f').format(encode.encode_args(math.inf))
945        self.assertTrue(result.ok())
946        self.assertEqual(result.value, 'inf')
947        self.assertEqual(result.remaining, b'')
948
949    def test_lowercase_float_non_number_zero(self) -> None:
950        result = decode.FormatString('%05f').format(
951            encode.encode_args(math.inf)
952        )
953        self.assertTrue(result.ok())
954        self.assertEqual(result.value, '  inf')
955        self.assertEqual(result.remaining, b'')
956
957    def test_lowercase_float_non_number_with_width(self) -> None:
958        result = decode.FormatString('%9f').format(encode.encode_args(math.inf))
959        self.assertTrue(result.ok())
960        self.assertEqual(result.value, '      inf')
961
962    def test_lowercase_float_non_number_with_multidigit_width(self) -> None:
963        result = decode.FormatString('%10f').format(
964            encode.encode_args(math.inf)
965        )
966        self.assertTrue(result.ok())
967        self.assertEqual(result.value, '       inf')
968
969    def test_lowercase_float_non_number_with_star_width(self) -> None:
970        result = decode.FormatString('%*f').format(
971            encode.encode_args(10, math.inf)
972        )
973        self.assertTrue(result.ok())
974        self.assertEqual(result.value, '       inf')
975
976    def test_lowercase_float_non_number_with_precision(self) -> None:
977        result = decode.FormatString('%.4f').format(
978            encode.encode_args(math.inf)
979        )
980        self.assertTrue(result.ok())
981        self.assertEqual(result.value, 'inf')
982
983    def test_lowercase_float_non_number_with_multidigit_precision(self) -> None:
984        result = decode.FormatString('%.10f').format(
985            encode.encode_args(math.inf)
986        )
987        self.assertTrue(result.ok())
988        self.assertEqual(result.value, 'inf')
989
990    def test_lowercase_float_non_number_with_star_preision(self) -> None:
991        result = decode.FormatString('%.*f').format(
992            encode.encode_args(10, math.inf)
993        )
994        self.assertTrue(result.ok())
995        self.assertEqual(result.value, 'inf')
996
997    def test_lowercase_float_non_number_with_zero_precision(self) -> None:
998        result = decode.FormatString('%.0f').format(
999            encode.encode_args(math.inf)
1000        )
1001        self.assertTrue(result.ok())
1002        self.assertEqual(result.value, 'inf')
1003
1004    def test_lowercase_float_non_number_with_empty_precision(self) -> None:
1005        result = decode.FormatString('%.f').format(encode.encode_args(math.inf))
1006        self.assertTrue(result.ok())
1007        self.assertEqual(result.value, 'inf')
1008
1009    def test_lowercase_float_non_number_with_width_and_precision(self) -> None:
1010        result = decode.FormatString('%10.0f').format(
1011            encode.encode_args(math.inf)
1012        )
1013        self.assertTrue(result.ok())
1014        self.assertEqual(result.value, '       inf')
1015
1016    def test_lowercase_float_non_number_with_star_width_and_star_precision(
1017        self,
1018    ) -> None:
1019        result = decode.FormatString('%*.*f').format(
1020            encode.encode_args(10, 0, math.inf)
1021        )
1022        self.assertTrue(result.ok())
1023        self.assertEqual(result.value, '       inf')
1024
1025    def test_zero_with_zero_precision(self) -> None:
1026        result = decode.FormatString('%.0f').format(encode.encode_args(0.0))
1027        self.assertTrue(result.ok())
1028        self.assertEqual(result.value, '0')
1029
1030    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1031
1032    def test_uppercase_float(self) -> None:
1033        result = decode.FormatString('%F').format(encode.encode_args(2.2))
1034        self.assertTrue(result.ok())
1035        self.assertEqual(result.value, '2.200000')
1036        self.assertEqual(result.remaining, b'')
1037
1038    def test_uppercase_float_with_length(self) -> None:
1039        """Tests that length modifiers do not affect F decoding."""
1040        result = decode.FormatString('%hhF').format(encode.encode_args(2.2))
1041        self.assertTrue(result.ok())
1042        self.assertEqual(result.value, '2.200000')
1043        self.assertEqual(result.remaining, b'')
1044
1045        result = decode.FormatString('%hF').format(encode.encode_args(2.2))
1046        self.assertTrue(result.ok())
1047        self.assertEqual(result.value, '2.200000')
1048        self.assertEqual(result.remaining, b'')
1049
1050        result = decode.FormatString('%lF').format(encode.encode_args(2.2))
1051        self.assertTrue(result.ok())
1052        self.assertEqual(result.value, '2.200000')
1053        self.assertEqual(result.remaining, b'')
1054
1055        result = decode.FormatString('%llF').format(encode.encode_args(2.2))
1056        self.assertTrue(result.ok())
1057        self.assertEqual(result.value, '2.200000')
1058        self.assertEqual(result.remaining, b'')
1059
1060        result = decode.FormatString('%jF').format(encode.encode_args(2.2))
1061        self.assertTrue(result.ok())
1062        self.assertEqual(result.value, '2.200000')
1063        self.assertEqual(result.remaining, b'')
1064
1065        result = decode.FormatString('%zF').format(encode.encode_args(2.2))
1066        self.assertTrue(result.ok())
1067        self.assertEqual(result.value, '2.200000')
1068
1069        result = decode.FormatString('%tF').format(encode.encode_args(2.2))
1070        self.assertTrue(result.ok())
1071        self.assertEqual(result.value, '2.200000')
1072        self.assertEqual(result.remaining, b'')
1073        self.assertEqual(result.remaining, b'')
1074
1075        result = decode.FormatString('%LF').format(encode.encode_args(2.2))
1076        self.assertTrue(result.ok())
1077        self.assertEqual(result.value, '2.200000')
1078        self.assertEqual(result.remaining, b'')
1079
1080    def test_uppercase_float_non_number(self) -> None:
1081        result = decode.FormatString('%F').format(encode.encode_args(math.inf))
1082        self.assertTrue(result.ok())
1083        self.assertEqual(result.value, 'INF')
1084        self.assertEqual(result.remaining, b'')
1085
1086    def test_lowercase_exponential(self) -> None:
1087        result = decode.FormatString('%e').format(encode.encode_args(2.2))
1088        self.assertTrue(result.ok())
1089        self.assertEqual(result.value, '2.200000e+00')
1090        self.assertEqual(result.remaining, b'')
1091
1092    def test_lowercase_exponential_with_length(self) -> None:
1093        """Tests that length modifiers do not affect e decoding."""
1094        result = decode.FormatString('%hhe').format(encode.encode_args(2.2))
1095        self.assertTrue(result.ok())
1096        self.assertEqual(result.value, '2.200000e+00')
1097        self.assertEqual(result.remaining, b'')
1098
1099        # inclusive-language: disable
1100        result = decode.FormatString('%he').format(encode.encode_args(2.2))
1101        # inclusive-language: enable
1102        self.assertTrue(result.ok())
1103        self.assertEqual(result.value, '2.200000e+00')
1104        self.assertEqual(result.remaining, b'')
1105
1106        result = decode.FormatString('%le').format(encode.encode_args(2.2))
1107        self.assertTrue(result.ok())
1108        self.assertEqual(result.value, '2.200000e+00')
1109        self.assertEqual(result.remaining, b'')
1110
1111        result = decode.FormatString('%lle').format(encode.encode_args(2.2))
1112        self.assertTrue(result.ok())
1113        self.assertEqual(result.value, '2.200000e+00')
1114        self.assertEqual(result.remaining, b'')
1115
1116        result = decode.FormatString('%je').format(encode.encode_args(2.2))
1117        self.assertTrue(result.ok())
1118        self.assertEqual(result.value, '2.200000e+00')
1119        self.assertEqual(result.remaining, b'')
1120
1121        result = decode.FormatString('%ze').format(encode.encode_args(2.2))
1122        self.assertTrue(result.ok())
1123        self.assertEqual(result.value, '2.200000e+00')
1124        self.assertEqual(result.remaining, b'')
1125
1126        result = decode.FormatString('%te').format(encode.encode_args(2.2))
1127        self.assertTrue(result.ok())
1128        self.assertEqual(result.value, '2.200000e+00')
1129        self.assertEqual(result.remaining, b'')
1130
1131        result = decode.FormatString('%Le').format(encode.encode_args(2.2))
1132        self.assertTrue(result.ok())
1133        self.assertEqual(result.value, '2.200000e+00')
1134        self.assertEqual(result.remaining, b'')
1135
1136    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1137
1138    def test_uppercase_exponential(self) -> None:
1139        result = decode.FormatString('%E').format(encode.encode_args(2.2))
1140        self.assertTrue(result.ok())
1141        self.assertEqual(result.value, '2.200000E+00')
1142        self.assertEqual(result.remaining, b'')
1143
1144    def test_uppercase_exponential_with_length(self) -> None:
1145        """Tests that length modifiers do not affect E decoding."""
1146        result = decode.FormatString('%hhE').format(encode.encode_args(2.2))
1147        self.assertTrue(result.ok())
1148        self.assertEqual(result.value, '2.200000E+00')
1149        self.assertEqual(result.remaining, b'')
1150
1151        # inclusive-language: disable
1152        result = decode.FormatString('%hE').format(encode.encode_args(2.2))
1153        # inclusive-language: enable
1154        self.assertTrue(result.ok())
1155        self.assertEqual(result.value, '2.200000E+00')
1156        self.assertEqual(result.remaining, b'')
1157
1158        result = decode.FormatString('%lE').format(encode.encode_args(2.2))
1159        self.assertTrue(result.ok())
1160        self.assertEqual(result.value, '2.200000E+00')
1161        self.assertEqual(result.remaining, b'')
1162
1163        result = decode.FormatString('%llE').format(encode.encode_args(2.2))
1164        self.assertTrue(result.ok())
1165        self.assertEqual(result.value, '2.200000E+00')
1166        self.assertEqual(result.remaining, b'')
1167
1168        result = decode.FormatString('%jE').format(encode.encode_args(2.2))
1169        self.assertTrue(result.ok())
1170        self.assertEqual(result.value, '2.200000E+00')
1171        self.assertEqual(result.remaining, b'')
1172
1173        result = decode.FormatString('%zE').format(encode.encode_args(2.2))
1174        self.assertTrue(result.ok())
1175        self.assertEqual(result.value, '2.200000E+00')
1176        self.assertEqual(result.remaining, b'')
1177
1178        result = decode.FormatString('%tE').format(encode.encode_args(2.2))
1179        self.assertTrue(result.ok())
1180        self.assertEqual(result.value, '2.200000E+00')
1181        self.assertEqual(result.remaining, b'')
1182
1183        result = decode.FormatString('%LE').format(encode.encode_args(2.2))
1184        self.assertTrue(result.ok())
1185        self.assertEqual(result.value, '2.200000E+00')
1186        self.assertEqual(result.remaining, b'')
1187
1188    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1189
1190    def test_lowercase_shortest_take_normal(self) -> None:
1191        result = decode.FormatString('%g').format(encode.encode_args(2.2))
1192        self.assertTrue(result.ok())
1193        self.assertEqual(result.value, '2.2')
1194        self.assertEqual(result.remaining, b'')
1195
1196    def test_lowercase_shortest_take_exponential(self) -> None:
1197        result = decode.FormatString('%g').format(encode.encode_args(1048580.0))
1198        self.assertTrue(result.ok())
1199        self.assertEqual(result.value, '1.04858e+06')
1200        self.assertEqual(result.remaining, b'')
1201
1202    def test_lowercase_shortest_with_length(self) -> None:
1203        """Tests that length modifiers do not affect g decoding."""
1204        result = decode.FormatString('%hhg').format(encode.encode_args(2.2))
1205        self.assertTrue(result.ok())
1206        self.assertEqual(result.value, '2.2')
1207        self.assertEqual(result.remaining, b'')
1208
1209        result = decode.FormatString('%hg').format(encode.encode_args(2.2))
1210        self.assertTrue(result.ok())
1211        self.assertEqual(result.value, '2.2')
1212        self.assertEqual(result.remaining, b'')
1213
1214        result = decode.FormatString('%lg').format(encode.encode_args(2.2))
1215        self.assertTrue(result.ok())
1216        self.assertEqual(result.value, '2.2')
1217        self.assertEqual(result.remaining, b'')
1218
1219        result = decode.FormatString('%llg').format(encode.encode_args(2.2))
1220        self.assertTrue(result.ok())
1221        self.assertEqual(result.value, '2.2')
1222        self.assertEqual(result.remaining, b'')
1223
1224        result = decode.FormatString('%jg').format(encode.encode_args(2.2))
1225        self.assertTrue(result.ok())
1226        self.assertEqual(result.value, '2.2')
1227        self.assertEqual(result.remaining, b'')
1228
1229        result = decode.FormatString('%zg').format(encode.encode_args(2.2))
1230        self.assertTrue(result.ok())
1231        self.assertEqual(result.value, '2.2')
1232        self.assertEqual(result.remaining, b'')
1233
1234        result = decode.FormatString('%tg').format(encode.encode_args(2.2))
1235        self.assertTrue(result.ok())
1236        self.assertEqual(result.value, '2.2')
1237        self.assertEqual(result.remaining, b'')
1238
1239        result = decode.FormatString('%Lg').format(encode.encode_args(2.2))
1240        self.assertTrue(result.ok())
1241        self.assertEqual(result.value, '2.2')
1242        self.assertEqual(result.remaining, b'')
1243
1244    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1245
1246    def test_uppercase_shortest_take_normal(self) -> None:
1247        result = decode.FormatString('%G').format(encode.encode_args(2.2))
1248        self.assertTrue(result.ok())
1249        self.assertEqual(result.value, '2.2')
1250        self.assertEqual(result.remaining, b'')
1251
1252    def test_uppercase_shortest_take_exponential(self) -> None:
1253        result = decode.FormatString('%G').format(encode.encode_args(1048580.0))
1254        self.assertTrue(result.ok())
1255        self.assertEqual(result.value, '1.04858E+06')
1256        self.assertEqual(result.remaining, b'')
1257
1258    def test_uppercase_shortest_with_length(self) -> None:
1259        """Tests that length modifiers do not affect G decoding."""
1260        result = decode.FormatString('%hhG').format(encode.encode_args(2.2))
1261        self.assertTrue(result.ok())
1262        self.assertEqual(result.value, '2.2')
1263        self.assertEqual(result.remaining, b'')
1264
1265        result = decode.FormatString('%hG').format(encode.encode_args(2.2))
1266        self.assertTrue(result.ok())
1267        self.assertEqual(result.value, '2.2')
1268        self.assertEqual(result.remaining, b'')
1269
1270        result = decode.FormatString('%lG').format(encode.encode_args(2.2))
1271        self.assertTrue(result.ok())
1272        self.assertEqual(result.value, '2.2')
1273        self.assertEqual(result.remaining, b'')
1274
1275        result = decode.FormatString('%llG').format(encode.encode_args(2.2))
1276        self.assertTrue(result.ok())
1277        self.assertEqual(result.value, '2.2')
1278        self.assertEqual(result.remaining, b'')
1279
1280        result = decode.FormatString('%jG').format(encode.encode_args(2.2))
1281        self.assertTrue(result.ok())
1282        self.assertEqual(result.value, '2.2')
1283        self.assertEqual(result.remaining, b'')
1284
1285        result = decode.FormatString('%zG').format(encode.encode_args(2.2))
1286        self.assertTrue(result.ok())
1287        self.assertEqual(result.value, '2.2')
1288        self.assertEqual(result.remaining, b'')
1289
1290        result = decode.FormatString('%tG').format(encode.encode_args(2.2))
1291        self.assertTrue(result.ok())
1292        self.assertEqual(result.value, '2.2')
1293        self.assertEqual(result.remaining, b'')
1294
1295        result = decode.FormatString('%LG').format(encode.encode_args(2.2))
1296        self.assertTrue(result.ok())
1297        self.assertEqual(result.value, '2.2')
1298        self.assertEqual(result.remaining, b'')
1299
1300
1301class TestCharDecoding(unittest.TestCase):
1302    """Tests decoding character values."""
1303
1304    def test_char(self) -> None:
1305        result = decode.FormatString('%c').format(encode.encode_args(ord('c')))
1306        self.assertTrue(result.ok())
1307        self.assertEqual(result.value, 'c')
1308        self.assertEqual(result.remaining, b'')
1309
1310    def test_char_with_minus(self) -> None:
1311        result = decode.FormatString('%-5c').format(
1312            encode.encode_args(ord('c'))
1313        )
1314        self.assertTrue(result.ok())
1315        self.assertEqual(result.value, 'c    ')
1316        self.assertEqual(result.remaining, b'')
1317
1318    def test_char_with_plus(self) -> None:
1319        result = decode.FormatString('%+c').format(encode.encode_args(ord('c')))
1320        self.assertFalse(result.ok())
1321
1322    def test_char_with_blank_space(self) -> None:
1323        result = decode.FormatString('% c').format(encode.encode_args(ord('c')))
1324        self.assertFalse(result.ok())
1325
1326    def test_char_with_hashtag(self) -> None:
1327        result = decode.FormatString('%#c').format(encode.encode_args(ord('c')))
1328        self.assertFalse(result.ok())
1329
1330    def test_char_with_zero(self) -> None:
1331        result = decode.FormatString('%0c').format(encode.encode_args(ord('c')))
1332        self.assertFalse(result.ok())
1333
1334    def test_char_with_length(self) -> None:
1335        """Tests that length modifiers do not affectchar decoding."""
1336        result = decode.FormatString('%hhc').format(
1337            encode.encode_args(ord('c'))
1338        )
1339        self.assertTrue(result.ok())
1340        self.assertEqual(result.value, 'c')
1341        self.assertEqual(result.remaining, b'')
1342
1343        result = decode.FormatString('%hc').format(encode.encode_args(ord('c')))
1344        self.assertTrue(result.ok())
1345        self.assertEqual(result.value, 'c')
1346        self.assertEqual(result.remaining, b'')
1347
1348        result = decode.FormatString('%lc').format(encode.encode_args(ord('c')))
1349        self.assertTrue(result.ok())
1350        self.assertEqual(result.value, 'c')
1351        self.assertEqual(result.remaining, b'')
1352
1353        result = decode.FormatString('%llc').format(
1354            encode.encode_args(ord('c'))
1355        )
1356        self.assertTrue(result.ok())
1357        self.assertEqual(result.value, 'c')
1358        self.assertEqual(result.remaining, b'')
1359
1360        result = decode.FormatString('%jc').format(encode.encode_args(ord('c')))
1361        self.assertTrue(result.ok())
1362        self.assertEqual(result.value, 'c')
1363        self.assertEqual(result.remaining, b'')
1364
1365        result = decode.FormatString('%zc').format(encode.encode_args(ord('c')))
1366        self.assertTrue(result.ok())
1367        self.assertEqual(result.value, 'c')
1368        self.assertEqual(result.remaining, b'')
1369
1370        result = decode.FormatString('%tc').format(encode.encode_args(ord('c')))
1371        self.assertTrue(result.ok())
1372        self.assertEqual(result.value, 'c')
1373        self.assertEqual(result.remaining, b'')
1374
1375        result = decode.FormatString('%Lc').format(encode.encode_args(ord('c')))
1376        self.assertTrue(result.ok())
1377        self.assertEqual(result.value, 'c')
1378        self.assertEqual(result.remaining, b'')
1379
1380    def test_char_with_width(self) -> None:
1381        result = decode.FormatString('%5c').format(encode.encode_args(ord('c')))
1382        self.assertTrue(result.ok())
1383        self.assertEqual(result.value, '    c')
1384
1385    def test_char_with_multidigit_width(self) -> None:
1386        result = decode.FormatString('%10c').format(
1387            encode.encode_args(ord('c'))
1388        )
1389        self.assertTrue(result.ok())
1390        self.assertEqual(result.value, '         c')
1391
1392    def test_char_with_star_width(self) -> None:
1393        result = decode.FormatString('%*c').format(
1394            encode.encode_args(10, ord('c'))
1395        )
1396        self.assertTrue(result.ok())
1397        self.assertEqual(result.value, '         c')
1398
1399    def test_char_with_precision(self) -> None:
1400        result = decode.FormatString('%.4c').format(
1401            encode.encode_args(ord('c'))
1402        )
1403        self.assertFalse(result.ok())
1404
1405    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1406
1407    def test_long_char(self) -> None:
1408        result = decode.FormatString('%lc').format(encode.encode_args(ord('c')))
1409        self.assertTrue(result.ok())
1410        self.assertEqual(result.value, 'c')
1411        self.assertEqual(result.remaining, b'')
1412
1413    def test_long_char_with_hashtag(self) -> None:
1414        result = decode.FormatString('%#lc').format(
1415            encode.encode_args(ord('c'))
1416        )
1417        self.assertFalse(result.ok())
1418
1419    def test_long_char_with_zero(self) -> None:
1420        result = decode.FormatString('%0lc').format(
1421            encode.encode_args(ord('c'))
1422        )
1423        self.assertFalse(result.ok())
1424
1425
1426class TestStringDecoding(unittest.TestCase):
1427    """Tests decoding string values."""
1428
1429    def test_string(self) -> None:
1430        result = decode.FormatString('%s').format(encode.encode_args('hello'))
1431        self.assertTrue(result.ok())
1432        self.assertEqual(result.value, 'hello')
1433        self.assertEqual(result.remaining, b'')
1434
1435    def test_string_with_minus(self) -> None:
1436        result = decode.FormatString('%-6s').format(encode.encode_args('hello'))
1437        self.assertTrue(result.ok())
1438        self.assertEqual(result.value, 'hello ')
1439        self.assertEqual(result.remaining, b'')
1440
1441    def test_string_with_plus(self) -> None:
1442        result = decode.FormatString('%+s').format(encode.encode_args('hello'))
1443        self.assertFalse(result.ok())
1444
1445    def test_string_with_blank_space(self) -> None:
1446        result = decode.FormatString('% s').format(encode.encode_args('hello'))
1447        self.assertFalse(result.ok())
1448
1449    def test_string_with_hashtag(self) -> None:
1450        result = decode.FormatString('%#s').format(encode.encode_args('hello'))
1451        self.assertFalse(result.ok())
1452
1453    def test_string_with_zero(self) -> None:
1454        result = decode.FormatString('%0s').format(encode.encode_args('hello'))
1455        self.assertFalse(result.ok())
1456
1457    def test_string_with_length(self) -> None:
1458        """Tests that length modifiers do not affect string values (s)."""
1459        result = decode.FormatString('%hhs').format(encode.encode_args('hello'))
1460        self.assertTrue(result.ok())
1461        self.assertEqual(result.value, 'hello')
1462        self.assertEqual(result.remaining, b'')
1463
1464        result = decode.FormatString('%hs').format(encode.encode_args('hello'))
1465        self.assertTrue(result.ok())
1466        self.assertEqual(result.value, 'hello')
1467        self.assertEqual(result.remaining, b'')
1468
1469        result = decode.FormatString('%ls').format(encode.encode_args('hello'))
1470        self.assertTrue(result.ok())
1471        self.assertEqual(result.value, 'hello')
1472        self.assertEqual(result.remaining, b'')
1473
1474        result = decode.FormatString('%lls').format(encode.encode_args('hello'))
1475        self.assertTrue(result.ok())
1476        self.assertEqual(result.value, 'hello')
1477        self.assertEqual(result.remaining, b'')
1478
1479        result = decode.FormatString('%js').format(encode.encode_args('hello'))
1480        self.assertTrue(result.ok())
1481        self.assertEqual(result.value, 'hello')
1482        self.assertEqual(result.remaining, b'')
1483
1484        result = decode.FormatString('%zs').format(encode.encode_args('hello'))
1485        self.assertTrue(result.ok())
1486        self.assertEqual(result.value, 'hello')
1487        self.assertEqual(result.remaining, b'')
1488
1489        result = decode.FormatString('%ts').format(encode.encode_args('hello'))
1490        self.assertTrue(result.ok())
1491        self.assertEqual(result.value, 'hello')
1492        self.assertEqual(result.remaining, b'')
1493
1494        result = decode.FormatString('%Ls').format(encode.encode_args('hello'))
1495        self.assertTrue(result.ok())
1496        self.assertEqual(result.value, 'hello')
1497        self.assertEqual(result.remaining, b'')
1498
1499    def test_string_with_width(self) -> None:
1500        result = decode.FormatString('%6s').format(encode.encode_args('hello'))
1501        self.assertTrue(result.ok())
1502        self.assertEqual(result.value, ' hello')
1503
1504    def test_string_with_width_does_not_pad_a_string_with_same_length(
1505        self,
1506    ) -> None:
1507        result = decode.FormatString('%5s').format(encode.encode_args('hello'))
1508        self.assertTrue(result.ok())
1509        self.assertEqual(result.value, 'hello')
1510
1511    def test_string_with_multidigit_width(self) -> None:
1512        result = decode.FormatString('%10s').format(encode.encode_args('hello'))
1513        self.assertTrue(result.ok())
1514        self.assertEqual(result.value, '     hello')
1515
1516    def test_string_with_star_width(self) -> None:
1517        result = decode.FormatString('%*s').format(
1518            encode.encode_args(10, 'hello')
1519        )
1520        self.assertTrue(result.ok())
1521        self.assertEqual(result.value, '     hello')
1522
1523    def test_string_with_precision(self) -> None:
1524        result = decode.FormatString('%.3s').format(encode.encode_args('hello'))
1525        self.assertTrue(result.ok())
1526        self.assertEqual(result.value, 'hel')
1527
1528    def test_string_with_multidigit_precision(self) -> None:
1529        result = decode.FormatString('%.10s').format(
1530            encode.encode_args('hello')
1531        )
1532        self.assertTrue(result.ok())
1533        self.assertEqual(result.value, 'hello')
1534
1535    def test_string_with_star_precision(self) -> None:
1536        result = decode.FormatString('%.*s').format(
1537            encode.encode_args(3, 'hello')
1538        )
1539        self.assertTrue(result.ok())
1540        self.assertEqual(result.value, 'hel')
1541
1542    def test_string_with_width_and_precision(self) -> None:
1543        result = decode.FormatString('%10.3s').format(
1544            encode.encode_args('hello')
1545        )
1546        self.assertTrue(result.ok())
1547        self.assertEqual(result.value, '       hel')
1548
1549    def test_string_with_star_with_and_star_precision(self) -> None:
1550        result = decode.FormatString('%*.*s').format(
1551            encode.encode_args(10, 3, 'hello')
1552        )
1553        self.assertTrue(result.ok())
1554        self.assertEqual(result.value, '       hel')
1555
1556    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1557
1558    def test_long_string(self) -> None:
1559        result = decode.FormatString('%ls').format(encode.encode_args('hello'))
1560        self.assertTrue(result.ok())
1561        self.assertEqual(result.value, 'hello')
1562        self.assertEqual(result.remaining, b'')
1563
1564    def test_long_string_with_hashtag(self) -> None:
1565        result = decode.FormatString('%#ls').format(encode.encode_args('hello'))
1566        self.assertFalse(result.ok())
1567        self.assertEqual(result.remaining, encode.encode_args('hello'))
1568
1569    def test_long_string_with_zero(self) -> None:
1570        result = decode.FormatString('%0ls').format(encode.encode_args('hello'))
1571        self.assertFalse(result.ok())
1572        self.assertEqual(result.remaining, encode.encode_args('hello'))
1573
1574
1575class TestPointerDecoding(unittest.TestCase):
1576    """Tests decoding pointer values."""
1577
1578    def test_pointer(self) -> None:
1579        result = decode.FormatString('%p').format(
1580            encode.encode_args(0xDEADBEEF)
1581        )
1582        self.assertTrue(result.ok())
1583        self.assertEqual(result.value, '0xDEADBEEF')
1584        self.assertEqual(result.remaining, b'')
1585
1586    def test_pointer_with_minus(self) -> None:
1587        result = decode.FormatString('%-12p').format(
1588            encode.encode_args(0xDEADBEEF)
1589        )
1590        self.assertTrue(result.ok())
1591        self.assertEqual(result.value, '0xDEADBEEF  ')
1592        self.assertEqual(result.remaining, b'')
1593
1594    def test_pointer_with_plus(self) -> None:
1595        result = decode.FormatString('%+p').format(
1596            encode.encode_args(0xDEADBEEF)
1597        )
1598        self.assertTrue(result.ok())
1599        self.assertEqual(result.value, '+0xDEADBEEF')
1600        self.assertEqual(result.remaining, b'')
1601
1602    def test_pointer_with_blank_space(self) -> None:
1603        result = decode.FormatString('% p').format(
1604            encode.encode_args(0xDEADBEEF)
1605        )
1606        self.assertTrue(result.ok())
1607        self.assertEqual(result.value, ' 0xDEADBEEF')
1608        self.assertEqual(result.remaining, b'')
1609
1610    def test_pointer_with_hashtag(self) -> None:
1611        result = decode.FormatString('%#p').format(
1612            encode.encode_args(0xDEADBEEF)
1613        )
1614        self.assertFalse(result.ok())
1615        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1616
1617    def test_pointer_with_zero(self) -> None:
1618        result = decode.FormatString('%0p').format(
1619            encode.encode_args(0xDEADBEEF)
1620        )
1621        self.assertFalse(result.ok())
1622        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1623
1624    def test_pointer_with_length(self) -> None:
1625        """Tests that length modifiers do not affect decoding pointers (p)."""
1626        result = decode.FormatString('%hhp').format(
1627            encode.encode_args(0xDEADBEEF)
1628        )
1629        self.assertFalse(result.ok())
1630        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1631
1632        result = decode.FormatString('%hp').format(
1633            encode.encode_args(0xDEADBEEF)
1634        )
1635        self.assertFalse(result.ok())
1636        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1637
1638        result = decode.FormatString('%lp').format(
1639            encode.encode_args(0xDEADBEEF)
1640        )
1641        self.assertFalse(result.ok())
1642        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1643
1644        result = decode.FormatString('%llp').format(
1645            encode.encode_args(0xDEADBEEF)
1646        )
1647        self.assertFalse(result.ok())
1648        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1649
1650        result = decode.FormatString('%jp').format(
1651            encode.encode_args(0xDEADBEEF)
1652        )
1653        self.assertFalse(result.ok())
1654        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1655
1656        result = decode.FormatString('%zp').format(
1657            encode.encode_args(0xDEADBEEF)
1658        )
1659        self.assertFalse(result.ok())
1660        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1661
1662        result = decode.FormatString('%tp').format(
1663            encode.encode_args(0xDEADBEEF)
1664        )
1665        self.assertFalse(result.ok())
1666        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1667
1668        result = decode.FormatString('%Lp').format(
1669            encode.encode_args(0xDEADBEEF)
1670        )
1671        self.assertFalse(result.ok())
1672        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1673
1674    def test_pointer_with_width(self) -> None:
1675        result = decode.FormatString('%9p').format(
1676            encode.encode_args(0xDEADBEEF)
1677        )
1678        self.assertTrue(result.ok())
1679        self.assertEqual(result.value, '0xDEADBEEF')
1680        self.assertEqual(result.remaining, b'')
1681
1682    def test_pointer_with_multidigit_width(self) -> None:
1683        result = decode.FormatString('%11p').format(
1684            encode.encode_args(0xDEADBEEF)
1685        )
1686        self.assertTrue(result.ok())
1687        self.assertEqual(result.value, ' 0xDEADBEEF')
1688        self.assertEqual(result.remaining, b'')
1689
1690    def test_pointer_with_star_width(self) -> None:
1691        result = decode.FormatString('%*p').format(
1692            encode.encode_args(10, 0xDEADBEEF)
1693        )
1694        self.assertTrue(result.ok())
1695        self.assertEqual(result.value, '0xDEADBEEF')
1696        self.assertEqual(result.remaining, b'')
1697
1698        result = decode.FormatString('%*p').format(
1699            encode.encode_args(15, 0xDEADBEEF)
1700        )
1701        self.assertTrue(result.ok())
1702        self.assertEqual(result.value, '     0xDEADBEEF')
1703        self.assertEqual(result.remaining, b'')
1704
1705    def test_pointer_with_precision(self) -> None:
1706        result = decode.FormatString('%.10p').format(
1707            encode.encode_args(0xDEADBEEF)
1708        )
1709        self.assertFalse(result.ok())
1710        self.assertEqual(result.remaining, encode.encode_args(0xDEADBEEF))
1711
1712    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1713
1714    def test_pointer_0_padding(self) -> None:
1715        result = decode.FormatString('%p').format(
1716            encode.encode_args(0x00000000)
1717        )
1718        self.assertTrue(result.ok())
1719        self.assertEqual(result.value, '0x00000000')
1720        self.assertEqual(result.remaining, b'')
1721
1722    def test_pointer_0_with_width(self) -> None:
1723        result = decode.FormatString('%9p').format(
1724            encode.encode_args(0x00000000)
1725        )
1726        self.assertTrue(result.ok())
1727        self.assertEqual(result.value, '0x00000000')
1728        self.assertEqual(result.remaining, b'')
1729
1730    def test_pointer_0_with_multidigit_width(self) -> None:
1731        result = decode.FormatString('%11p').format(
1732            encode.encode_args(0x00000000)
1733        )
1734        self.assertTrue(result.ok())
1735        self.assertEqual(result.value, ' 0x00000000')
1736        self.assertEqual(result.remaining, b'')
1737
1738    def test_pointer_0_with_star_width(self) -> None:
1739        result = decode.FormatString('%*p').format(
1740            encode.encode_args(10, 0x00000000)
1741        )
1742        self.assertTrue(result.ok())
1743        self.assertEqual(result.value, '0x00000000')
1744        self.assertEqual(result.remaining, b'')
1745
1746        result = decode.FormatString('%*p').format(
1747            encode.encode_args(15, 0x00000000)
1748        )
1749        self.assertTrue(result.ok())
1750        self.assertEqual(result.value, '     0x00000000')
1751        self.assertEqual(result.remaining, b'')
1752
1753
1754class TestFormattedString(unittest.TestCase):
1755    """Tests scoring how successfully a formatted string decoded."""
1756
1757    def test_no_args(self) -> None:
1758        result = decode.FormatString('string').format(b'')
1759
1760        self.assertTrue(result.ok())
1761        self.assertEqual(result.score(), (True, True, 0, 0, datetime.max))
1762
1763    def test_one_arg(self) -> None:
1764        result = decode.FormatString('%d').format(encode.encode_args(0))
1765
1766        self.assertTrue(result.ok())
1767        self.assertEqual(result.score(), (True, True, 0, 1, datetime.max))
1768
1769    def test_missing_args(self) -> None:
1770        result = decode.FormatString('%p%d%d').format(b'\x02\x80')
1771
1772        self.assertFalse(result.ok())
1773        self.assertEqual(result.score(), (False, True, -2, 3, datetime.max))
1774        self.assertGreater(result.score(), result.score(datetime.now()))
1775        self.assertGreater(
1776            result.score(datetime.now()), result.score(datetime.min)
1777        )
1778
1779    def test_compare_score(self) -> None:
1780        all_args_ok = decode.FormatString('%d%d%d').format(
1781            encode.encode_args(0, 0, 0)
1782        )
1783        missing_one_arg = decode.FormatString('%d%d%d').format(
1784            encode.encode_args(0, 0)
1785        )
1786        missing_two_args = decode.FormatString('%d%d%d').format(
1787            encode.encode_args(0)
1788        )
1789        all_args_extra_data = decode.FormatString('%d%d%d').format(
1790            encode.encode_args(0, 0, 0, 1)
1791        )
1792        missing_one_arg_extra_data = decode.FormatString('%d%d%d').format(
1793            b'\0' + b'\x80' * 100
1794        )
1795
1796        self.assertGreater(all_args_ok.score(), missing_one_arg.score())
1797        self.assertGreater(missing_one_arg.score(), missing_two_args.score())
1798        self.assertGreater(
1799            missing_two_args.score(), all_args_extra_data.score()
1800        )
1801        self.assertGreater(
1802            all_args_extra_data.score(), missing_one_arg_extra_data.score()
1803        )
1804
1805
1806if __name__ == '__main__':
1807    unittest.main()
1808