|
| 1 | +from eth2spec.test import context |
| 2 | +from eth_utils import encode_hex |
| 3 | +from ruamel.yaml import YAML |
| 4 | +from snappy import compress |
| 5 | + |
| 6 | +from .gen_typing import TestCase |
| 7 | + |
| 8 | + |
| 9 | +def get_default_yaml(): |
| 10 | + yaml = YAML(pure=True) |
| 11 | + yaml.default_flow_style = None |
| 12 | + |
| 13 | + def _represent_none(self, _): |
| 14 | + return self.represent_scalar("tag:yaml.org,2002:null", "null") |
| 15 | + |
| 16 | + def _represent_str(self, data): |
| 17 | + if data.startswith("0x"): |
| 18 | + # Without this, a zero-byte hex string is represented without quotes. |
| 19 | + return self.represent_scalar("tag:yaml.org,2002:str", data, style="'") |
| 20 | + return self.represent_str(data) |
| 21 | + |
| 22 | + yaml.representer.add_representer(type(None), _represent_none) |
| 23 | + yaml.representer.add_representer(str, _represent_str) |
| 24 | + |
| 25 | + return yaml |
| 26 | + |
| 27 | + |
| 28 | +def get_cfg_yaml(): |
| 29 | + # Spec config is using a YAML subset |
| 30 | + cfg_yaml = YAML(pure=True) |
| 31 | + cfg_yaml.default_flow_style = False # Emit separate line for each key |
| 32 | + |
| 33 | + def cfg_represent_bytes(self, data): |
| 34 | + return self.represent_int(encode_hex(data)) |
| 35 | + |
| 36 | + cfg_yaml.representer.add_representer(bytes, cfg_represent_bytes) |
| 37 | + |
| 38 | + def cfg_represent_quoted_str(self, data): |
| 39 | + return self.represent_scalar("tag:yaml.org,2002:str", data, style="'") |
| 40 | + |
| 41 | + cfg_yaml.representer.add_representer(context.quoted_str, cfg_represent_quoted_str) |
| 42 | + return cfg_yaml |
| 43 | + |
| 44 | + |
| 45 | +class Dumper: |
| 46 | + """Helper for dumping test case outputs (cfg, data, meta, ssz).""" |
| 47 | + |
| 48 | + def __init__(self, default_yaml: YAML = None, cfg_yaml: YAML = None): |
| 49 | + self.default_yaml = default_yaml or get_default_yaml() |
| 50 | + self.cfg_yaml = cfg_yaml or get_cfg_yaml() |
| 51 | + |
| 52 | + def dump_meta(self, test_case: TestCase, meta: dict) -> None: |
| 53 | + if not meta: |
| 54 | + return |
| 55 | + self._dump_yaml(test_case, "meta", meta, self.default_yaml) |
| 56 | + |
| 57 | + def dump_cfg(self, test_case: TestCase, name: str, data: any) -> None: |
| 58 | + self._dump_yaml(test_case, name, data, self.cfg_yaml) |
| 59 | + |
| 60 | + def dump_data(self, test_case: TestCase, name: str, data: any) -> None: |
| 61 | + self._dump_yaml(test_case, name, data, self.default_yaml) |
| 62 | + |
| 63 | + def dump_ssz(self, test_case: TestCase, name: str, data: bytes) -> None: |
| 64 | + """Compress and write SSZ data for test case.""" |
| 65 | + path = test_case.dir / f"{name}.ssz_snappy" |
| 66 | + path.parent.mkdir(parents=True, exist_ok=True) |
| 67 | + with path.open("wb") as f: |
| 68 | + f.write(compress(data)) |
| 69 | + |
| 70 | + def _dump_yaml(self, test_case: TestCase, name: str, data: any, yaml_encoder: YAML) -> None: |
| 71 | + """Helper to write YAML files for test case.""" |
| 72 | + path = test_case.dir / f"{name}.yaml" |
| 73 | + path.parent.mkdir(parents=True, exist_ok=True) |
| 74 | + with path.open("w") as f: |
| 75 | + yaml_encoder.dump(data, f) |
0 commit comments