|
| 1 | +#!/bin/bash |
| 2 | +# leanSpec module import coverage test. |
| 3 | +# Attempts to import each leanSpec source module through the LeanPython interpreter. |
| 4 | +# Reports PASS / XFAIL (expected failure with issue#) / FAIL (unexpected). |
| 5 | +# |
| 6 | +# Usage: ./test_leanspec_imports.sh |
| 7 | + |
| 8 | +set -euo pipefail |
| 9 | + |
| 10 | +EXE=".lake/build/bin/leanPython" |
| 11 | +SRC="/home/zksecurity/leanPython/references/leanSpec/src" |
| 12 | + |
| 13 | +if [ ! -f "$EXE" ]; then |
| 14 | + echo "error: $EXE not found — run 'lake build' first" |
| 15 | + exit 1 |
| 16 | +fi |
| 17 | + |
| 18 | +PASS=0 |
| 19 | +FAIL=0 |
| 20 | +XFAIL=0 |
| 21 | +FAILURES="" |
| 22 | + |
| 23 | +# Expected failures: module_pattern -> "issue_number reason" |
| 24 | +# Modules matching these patterns are XFAIL (expected to fail). |
| 25 | +declare -A XFAIL_MAP |
| 26 | + |
| 27 | +# #5: lean_multisig_py (pending pure Python impl) |
| 28 | +XFAIL_MAP["lean_spec.subspecs.xmss.aggregation"]="#5 lean_multisig_py" |
| 29 | +# Transitive: everything importing xmss.aggregation |
| 30 | +XFAIL_MAP["lean_spec.subspecs.xmss.interface"]="#5 imports aggregation transitively" |
| 31 | +XFAIL_MAP["lean_spec.subspecs.containers.attestation.attestation"]="#5 imports xmss.aggregation" |
| 32 | +XFAIL_MAP["lean_spec.subspecs.containers.block.block"]="#5 imports xmss.aggregation" |
| 33 | +XFAIL_MAP["lean_spec.subspecs.containers.block.types"]="#4,#5 dict subclass + xmss.aggregation" |
| 34 | +XFAIL_MAP["lean_spec.subspecs.containers.state.state"]="#5 imports xmss.aggregation" |
| 35 | +XFAIL_MAP["lean_spec.subspecs.containers.validator"]="#5 imports xmss.containers->config" |
| 36 | +XFAIL_MAP["lean_spec.subspecs.containers.attestation.aggregation_bits"]="#5 imports validator->xmss" |
| 37 | +XFAIL_MAP["lean_spec.subspecs.containers.state.types"]="#5 imports validator->xmss" |
| 38 | + |
| 39 | +# #5: XMSS modules that need lean_spec.config (get_args / PEP 695 __value__) |
| 40 | +XFAIL_MAP["lean_spec.config"]="#5 get_args + PEP695 __value__" |
| 41 | +XFAIL_MAP["lean_spec.subspecs.xmss.constants"]="#5 imports lean_spec.config" |
| 42 | +XFAIL_MAP["lean_spec.subspecs.xmss.types"]="#5 imports xmss.constants" |
| 43 | +XFAIL_MAP["lean_spec.subspecs.xmss.containers"]="#5 imports xmss.constants" |
| 44 | +XFAIL_MAP["lean_spec.subspecs.xmss._validation"]="#5 imports lean_spec.config" |
| 45 | +XFAIL_MAP["lean_spec.subspecs.xmss.hypercube"]="#5 imports xmss.constants" |
| 46 | +XFAIL_MAP["lean_spec.subspecs.xmss.message_hash"]="#5 imports xmss chain" |
| 47 | +XFAIL_MAP["lean_spec.subspecs.xmss.poseidon"]="#5 imports xmss chain" |
| 48 | +XFAIL_MAP["lean_spec.subspecs.xmss.prf"]="#5 imports xmss.constants" |
| 49 | +XFAIL_MAP["lean_spec.subspecs.xmss.rand"]="#5 imports xmss.constants" |
| 50 | +XFAIL_MAP["lean_spec.subspecs.xmss.subtree"]="#5 imports xmss.types" |
| 51 | +XFAIL_MAP["lean_spec.subspecs.xmss.target_sum"]="#5 imports xmss.constants" |
| 52 | +XFAIL_MAP["lean_spec.subspecs.xmss.tweak_hash"]="#5 imports xmss chain" |
| 53 | +XFAIL_MAP["lean_spec.subspecs.xmss.utils"]="#5 imports xmss chain" |
| 54 | + |
| 55 | +# #6: numpy/numba (pending pure Python impl) |
| 56 | +XFAIL_MAP["lean_spec.subspecs.poseidon2.permutation"]="#6 numpy" |
| 57 | +XFAIL_MAP["lean_spec.subspecs.poseidon2.constants"]="#6 imports permutation transitively" |
| 58 | + |
| 59 | +# #7: asyncio |
| 60 | +XFAIL_MAP["lean_spec.__main__"]="#7 asyncio" |
| 61 | +XFAIL_MAP["lean_spec.subspecs.chain.clock"]="#7 asyncio" |
| 62 | +XFAIL_MAP["lean_spec.subspecs.chain.service"]="#7 asyncio" |
| 63 | +XFAIL_MAP["lean_spec.subspecs.api.server"]="#7 asyncio" |
| 64 | +XFAIL_MAP["lean_spec.subspecs.api.routes"]="#7 imports api.server" |
| 65 | +XFAIL_MAP["lean_spec.subspecs.api.endpoints.checkpoints"]="#7 imports api chain" |
| 66 | +XFAIL_MAP["lean_spec.subspecs.api.endpoints.fork_choice"]="#7 imports api chain" |
| 67 | +XFAIL_MAP["lean_spec.subspecs.api.endpoints.health"]="#7 imports api chain" |
| 68 | +XFAIL_MAP["lean_spec.subspecs.api.endpoints.metrics"]="#7 imports api chain" |
| 69 | +XFAIL_MAP["lean_spec.subspecs.api.endpoints.states"]="#7 asyncio" |
| 70 | +XFAIL_MAP["lean_spec.subspecs.networking.client.event_source"]="#7 asyncio" |
| 71 | +XFAIL_MAP["lean_spec.subspecs.networking.client.reqresp_client"]="#7 asyncio" |
| 72 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.service"]="#7 asyncio" |
| 73 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.transport"]="#7 asyncio + cryptography" |
| 74 | +XFAIL_MAP["lean_spec.subspecs.networking.gossipsub.behavior"]="#7 asyncio" |
| 75 | +XFAIL_MAP["lean_spec.subspecs.networking.service.service"]="#7 asyncio" |
| 76 | +XFAIL_MAP["lean_spec.subspecs.networking.service.events"]="#7 imports service chain" |
| 77 | +XFAIL_MAP["lean_spec.subspecs.networking.transport.quic.connection"]="#7 asyncio + aioquic" |
| 78 | +XFAIL_MAP["lean_spec.subspecs.networking.transport.quic.stream_adapter"]="#7 asyncio" |
| 79 | +XFAIL_MAP["lean_spec.subspecs.node.node"]="#7 asyncio" |
| 80 | +XFAIL_MAP["lean_spec.subspecs.sync.service"]="#7 asyncio" |
| 81 | +XFAIL_MAP["lean_spec.subspecs.sync.backfill_sync"]="#7 imports sync chain" |
| 82 | +XFAIL_MAP["lean_spec.subspecs.sync.checkpoint_sync"]="#7 imports sync chain" |
| 83 | +XFAIL_MAP["lean_spec.subspecs.sync.head_sync"]="#7 imports sync chain" |
| 84 | +XFAIL_MAP["lean_spec.subspecs.validator.service"]="#7 asyncio" |
| 85 | +XFAIL_MAP["lean_spec.subspecs.validator.registry"]="#5,#7 imports xmss + chain" |
| 86 | + |
| 87 | +# chain/__init__.py imports clock.py which uses asyncio, blocking all chain.* imports |
| 88 | +XFAIL_MAP["lean_spec.subspecs.chain.config"]="#7 chain/__init__.py imports clock->asyncio" |
| 89 | +XFAIL_MAP["lean_spec.subspecs.containers.checkpoint"]="#7 imports chain->clock->asyncio" |
| 90 | +XFAIL_MAP["lean_spec.subspecs.containers.config"]="#7 imports chain->clock->asyncio" |
| 91 | +XFAIL_MAP["lean_spec.subspecs.containers.slot"]="#7 imports chain->clock->asyncio" |
| 92 | + |
| 93 | +# #9: prometheus_client |
| 94 | +XFAIL_MAP["lean_spec.subspecs.metrics.registry"]="#9 prometheus_client" |
| 95 | +XFAIL_MAP["lean_spec.subspecs.forkchoice.store"]="#5,#9 xmss + prometheus_client" |
| 96 | + |
| 97 | +# Other external deps (cryptography, aioquic, sqlite3) |
| 98 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.crypto"]="cryptography lib" |
| 99 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.keys"]="cryptography lib" |
| 100 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.handshake"]="cryptography lib" |
| 101 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.codec"]="imports discovery chain" |
| 102 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.config"]="imports discovery chain" |
| 103 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.messages"]="imports discovery chain" |
| 104 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.packet"]="imports discovery chain" |
| 105 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.routing"]="imports discovery chain" |
| 106 | +XFAIL_MAP["lean_spec.subspecs.networking.discovery.session"]="imports discovery chain" |
| 107 | +XFAIL_MAP["lean_spec.subspecs.networking.enr.enr"]="cryptography lib" |
| 108 | +XFAIL_MAP["lean_spec.subspecs.networking.enr.eth2"]="imports enr chain" |
| 109 | +XFAIL_MAP["lean_spec.subspecs.networking.enr.keys"]="cryptography lib" |
| 110 | +XFAIL_MAP["lean_spec.subspecs.networking.transport.identity.keypair"]="cryptography lib" |
| 111 | +XFAIL_MAP["lean_spec.subspecs.networking.transport.identity.signature"]="cryptography lib" |
| 112 | +XFAIL_MAP["lean_spec.subspecs.networking.transport.peer_id"]="imports identity chain" |
| 113 | +XFAIL_MAP["lean_spec.subspecs.networking.transport.protocols"]="imports transport chain" |
| 114 | +XFAIL_MAP["lean_spec.subspecs.networking.transport.quic.tls"]="aioquic + cryptography" |
| 115 | +XFAIL_MAP["lean_spec.subspecs.networking.peer"]="imports networking chain" |
| 116 | +XFAIL_MAP["lean_spec.subspecs.networking.config"]="imports networking chain" |
| 117 | +XFAIL_MAP["lean_spec.subspecs.networking.types"]="imports networking chain" |
| 118 | +XFAIL_MAP["lean_spec.subspecs.networking.varint"]="imports networking chain" |
| 119 | +XFAIL_MAP["lean_spec.subspecs.networking.reqresp.codec"]="imports networking chain" |
| 120 | +XFAIL_MAP["lean_spec.subspecs.networking.reqresp.handler"]="imports networking chain" |
| 121 | +XFAIL_MAP["lean_spec.subspecs.networking.reqresp.message"]="imports networking chain" |
| 122 | +XFAIL_MAP["lean_spec.subspecs.networking.gossipsub.mcache"]="imports networking chain" |
| 123 | +XFAIL_MAP["lean_spec.subspecs.networking.gossipsub.mesh"]="imports networking chain" |
| 124 | +XFAIL_MAP["lean_spec.subspecs.networking.gossipsub.message"]="imports networking chain" |
| 125 | +XFAIL_MAP["lean_spec.subspecs.networking.gossipsub.parameters"]="imports networking chain" |
| 126 | +XFAIL_MAP["lean_spec.subspecs.networking.gossipsub.rpc"]="imports networking chain" |
| 127 | +XFAIL_MAP["lean_spec.subspecs.networking.gossipsub.topic"]="imports networking chain" |
| 128 | +XFAIL_MAP["lean_spec.subspecs.networking.gossipsub.types"]="imports networking chain" |
| 129 | +XFAIL_MAP["lean_spec.subspecs.storage.sqlite"]="sqlite3" |
| 130 | +XFAIL_MAP["lean_spec.subspecs.storage.database"]="imports storage chain" |
| 131 | +XFAIL_MAP["lean_spec.subspecs.storage.exceptions"]="imports storage chain" |
| 132 | +XFAIL_MAP["lean_spec.subspecs.storage.namespaces"]="imports storage chain" |
| 133 | +XFAIL_MAP["lean_spec.subspecs.sync.block_cache"]="imports sync chain" |
| 134 | +XFAIL_MAP["lean_spec.subspecs.sync.config"]="imports sync chain" |
| 135 | +XFAIL_MAP["lean_spec.subspecs.sync.peer_manager"]="imports sync chain" |
| 136 | +XFAIL_MAP["lean_spec.subspecs.sync.states"]="imports sync chain" |
| 137 | +XFAIL_MAP["lean_spec.subspecs.genesis.config"]="#5 imports xmss chain" |
| 138 | +XFAIL_MAP["lean_spec.subspecs.genesis.state"]="#5 imports genesis.config" |
| 139 | + |
| 140 | +# --- Test runner --- |
| 141 | + |
| 142 | +MAIN_PY="$SRC/_leanpython_import_test.py" |
| 143 | +cleanup() { rm -f "$MAIN_PY"; } |
| 144 | +trap cleanup EXIT |
| 145 | + |
| 146 | +try_import() { |
| 147 | + local mod="$1" |
| 148 | + |
| 149 | + cat > "$MAIN_PY" << PYEOF |
| 150 | +import $mod |
| 151 | +PYEOF |
| 152 | + |
| 153 | + local output |
| 154 | + output=$(timeout 30 "$EXE" "$MAIN_PY" 2>&1) || true |
| 155 | + |
| 156 | + if [ -z "$output" ]; then |
| 157 | + return 0 # success (no output = no error) |
| 158 | + else |
| 159 | + echo "$output" |
| 160 | + return 1 |
| 161 | + fi |
| 162 | +} |
| 163 | + |
| 164 | +echo "=== LeanPython leanSpec import coverage ===" |
| 165 | +echo "" |
| 166 | + |
| 167 | +# Collect all modules |
| 168 | +MODULES=$(find "$SRC/lean_spec" -name "*.py" -not -name "__init__.py" -not -path "*__pycache__*" \ |
| 169 | + | sed "s|$SRC/||; s|/|.|g; s|\.py$||" | sort) |
| 170 | + |
| 171 | +for mod in $MODULES; do |
| 172 | + xfail_reason="${XFAIL_MAP[$mod]:-}" |
| 173 | + |
| 174 | + output=$(try_import "$mod" 2>&1) && ok=true || ok=false |
| 175 | + |
| 176 | + if $ok; then |
| 177 | + if [ -n "$xfail_reason" ]; then |
| 178 | + # Unexpectedly passed — still good, report as PASS |
| 179 | + printf " PASS %-60s (was xfail: %s)\n" "$mod" "$xfail_reason" |
| 180 | + else |
| 181 | + printf " PASS %s\n" "$mod" |
| 182 | + fi |
| 183 | + PASS=$((PASS + 1)) |
| 184 | + else |
| 185 | + if [ -n "$xfail_reason" ]; then |
| 186 | + printf " XFAIL %-60s [%s]\n" "$mod" "$xfail_reason" |
| 187 | + XFAIL=$((XFAIL + 1)) |
| 188 | + else |
| 189 | + printf " FAIL %s\n" "$mod" |
| 190 | + FAILURES="$FAILURES\n $mod: $(echo "$output" | head -1)" |
| 191 | + FAIL=$((FAIL + 1)) |
| 192 | + fi |
| 193 | + fi |
| 194 | +done |
| 195 | + |
| 196 | +echo "" |
| 197 | +echo "Results: $PASS pass, $FAIL fail, $XFAIL xfail (expected)" |
| 198 | + |
| 199 | +if [ $FAIL -gt 0 ]; then |
| 200 | + echo "" |
| 201 | + echo "Unexpected failures:" |
| 202 | + printf "$FAILURES\n" |
| 203 | + exit 1 |
| 204 | +fi |
| 205 | + |
| 206 | +exit 0 |
0 commit comments