54 lines
2.3 KiB
Python
54 lines
2.3 KiB
Python
|
|
"""Verify the public format through an independent Python implementation."""
|
||
|
|
|
||
|
|
import importlib.util
|
||
|
|
import math
|
||
|
|
from pathlib import Path
|
||
|
|
import struct
|
||
|
|
import subprocess
|
||
|
|
import sys
|
||
|
|
import tempfile
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
"""Check native/text equality and CSV output using files produced by C++."""
|
||
|
|
sys.dont_write_bytecode = True
|
||
|
|
writer, reader_path = sys.argv[1:]
|
||
|
|
spec = importlib.util.spec_from_file_location("serif_archive", reader_path)
|
||
|
|
module = importlib.util.module_from_spec(spec)
|
||
|
|
spec.loader.exec_module(module)
|
||
|
|
with tempfile.TemporaryDirectory(prefix="serif-python-reader-") as directory:
|
||
|
|
subprocess.run([writer, directory], check=True)
|
||
|
|
representations = []
|
||
|
|
for encoding in ("binary", "text"):
|
||
|
|
path = Path(directory) / f"{encoding}.serif"
|
||
|
|
with module.Archive(path) as archive:
|
||
|
|
values = archive.read("values")
|
||
|
|
assert len(values) == 5
|
||
|
|
assert math.copysign(1.0, values[0]) < 0
|
||
|
|
assert values[1] == 1.2345678901234567
|
||
|
|
assert values[2] == float.fromhex("0x0.0000000000001p-1022")
|
||
|
|
assert values[3] == math.inf
|
||
|
|
assert struct.pack("<d", values[4]).hex() == "bc9a78563412f87f"
|
||
|
|
assert archive.read("integers") == [-(1 << 63), (1 << 63) - 1]
|
||
|
|
assert archive.read("label") == 'ξ\n"quote"\\end'
|
||
|
|
assert archive.read("empty") == []
|
||
|
|
assert archive.read("provenance/author") == "Cross-language regression"
|
||
|
|
representations.append(struct.pack("<5d", *values))
|
||
|
|
csv = subprocess.run([sys.executable, reader_path, str(path), "--read", "values", "--csv"], check=True, capture_output=True, text=True).stdout
|
||
|
|
assert csv.startswith("index,value\n0,-0.0\n")
|
||
|
|
damaged = bytearray(path.read_bytes())
|
||
|
|
damaged[550] ^= 1
|
||
|
|
path.write_bytes(damaged)
|
||
|
|
try:
|
||
|
|
module.Archive(path)
|
||
|
|
except ValueError as error:
|
||
|
|
assert "ledger" in str(error)
|
||
|
|
else:
|
||
|
|
raise AssertionError("Corrupted ledger was accepted")
|
||
|
|
assert representations[0] == representations[1]
|
||
|
|
print("Python reader: binary/text exact values, provenance, CSV and corruption checks passed")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|