diff options
| author | eunhhu <[email protected]> | 2026-10-19 02:28:34 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-19 02:28:34 +0100 |
| commit | ca214af2684b3c6e6982d1fe8be4e7ecc0849b00 (patch) | |
| tree | 9710ca0c2e1671ea03ae17980632bcd5fbf03f6f /tests | |
| parent | f12346827a136536c5e8e9c6af3da842bd5cc0c3 (diff) | |
| download | pure-ca214af2684b3c6e6982d1fe8be4e7ecc0849b00.tar.gz pure-ca214af2684b3c6e6982d1fe8be4e7ecc0849b00.zip | |
140's 3, inflate (RFC 1951), written in aup with no new opcode (aup's examples/inflate.aup, codes read a bit at a time from canonical counts as zlib's puff.c): 640 streams zlib made (6,488,480 bytes: random bytes, words, runs and repeats 32,768 back; levels 0, 1, 6, 9 and zlib's five strategies, so stored, fixed and dynamic blocks) inflated to the original's bytes on the three paths, the paths' outputs the same bytes; 240 damaged streams (cut, a bit flipped) read as inflate.py (the Python reference) reads them, 165 refused by both and 75 the same bytes; module_specs in make check: 144 streams on the three paths, 21 cut ones failing and leaving the last bytes; bars: written (no new opcode), three workarounds (lists passed in records: a fn takes no list; the output a list of one: a bytes value is no state; a block's tables built in a fn: a let's list lives in the handler's own block), 132 lines against Python's 81, 1,152 ns an output byte against the same algorithm in C 10.7 (108x) and zlib 3.5 (329x), pure Python 1,214; 191 instructions a byte (a block fn called for each bit was 246 and 1,553 ns: small block fns' inlining is 2c's leftover); the four timing tools' message calls fixed for 4b's API (no keys); CHECKPOINT's direction row
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/check.py | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/tests/check.py b/tests/check.py index 3f2fee1..4f2fb98 100644 --- a/tests/check.py +++ b/tests/check.py @@ -1729,7 +1729,9 @@ def module_specs(aup, pure, work): messages of every length up to two blocks; whether bytes are JSON (its examples/json.aup) on JSONTestSuite's parsing cases (tests/specs/json): every y_ case taken, every n_ case refused (a refusal: valid false, or - the event failing as encoding on bytes that are not UTF-8).""" + the event failing as encoding on bytes that are not UTF-8); JSON read into + a tree (its examples/json_tree.aup); raw deflate streams zlib made inflated + by its examples/inflate.aup to the original's bytes, cut ones refused.""" import hashlib import os import random @@ -1829,6 +1831,39 @@ def module_specs(aup, pure, work): assert {k: state['states'][k] for k in keys} == digest(cases[name]), name trees[name[0]] += accepted runs['json_tree'] = {'cases': len(cases), 'taken': trees} + # inflate (RFC 1951, its examples/inflate.aup): raw deflate streams zlib made (stored, fixed and dynamic blocks, its + # strategies, words, runs and repeats 32,768 bytes back), each inflated to the original's bytes; a stream cut short + # fails its event and leaves the last stream's bytes. + import zlib + program = work / 'inflate.pmod' + compile_module(aup, EXAMPLES / 'inflate.aup', program) + words = [bytes(chooser.choices(b'abcdefghijklmnopqrstuvwxyz', k=chooser.randrange(2, 9))) for _ in range(200)] + streams = [] + for size in (0, 1, 100, 1000, 10000, 40000): + far = bytes(chooser.randrange(256) for _ in range(min(size, 33000))) + for data in (bytes(chooser.randrange(256) for _ in range(size)), b' '.join(chooser.choice(words) for _ in range(size))[:size], + (b'abaabbb' * size)[:size], (far + far[:32768])[:size]): + for level, strategy in ((0, zlib.Z_DEFAULT_STRATEGY), (6, zlib.Z_DEFAULT_STRATEGY), (9, zlib.Z_FILTERED), + (6, zlib.Z_HUFFMAN_ONLY), (6, zlib.Z_RLE), (9, zlib.Z_FIXED)): + packer = zlib.compressobj(level, zlib.DEFLATED, -15, 9, strategy) + streams.append((data, packer.compress(data) + packer.flush())) + cut = [(data, packed[:len(packed) // 2]) for data, packed in streams[::7] if len(packed) > 1] + given = '' + for n, (_, packed) in enumerate(streams + cut): + (work / f'{n}.deflate').write_bytes(packed) + given += f'message inflate @{work / f"{n}.deflate"}\n' + outputs = {name: subprocess.run([str(pure / 'build/pure-run'), str(program)], input=given, capture_output=True, text=True, + timeout=600, env=dict(os.environ, **env)).stdout + for name, env in (('batches', {'PURE_JIT': '0'}), ('rounds', {'PURE_JIT': '0', 'PURE_BATCH': '0'}), ('all', {'PURE_JIT': 'all'}))} + for name in ('rounds', 'all'): + assert outputs[name] == outputs['batches'], ('inflate', name) + shown = [json.loads(line) for line in outputs['batches'].splitlines()] + assert len(shown) == len(streams) + len(cut), ('inflate', len(shown)) + for (data, _), state in zip(streams, shown): + assert state['fault'] == 'none' and state['states']['inflated'][-1]['data'] == data.hex(), ('inflate', len(data)) + for state in shown[len(streams):]: + assert state['fault'] != 'none' and state['states']['inflated'][-1]['data'] == streams[-1][0].hex(), ('inflate cut', state['fault']) + runs['inflate'] = {'streams': len(streams), 'bytes': sum(len(d) for d, _ in streams), 'cut': len(cut)} return runs |
