java-topology/defects/wasabi-0002/test/wasabi-0002-test.py

94 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""Unit test: wasabi-0002 TransactionFactory AllowedInputs O(C*A) -> O(C) HashSet"""
import sys
class FakeOutPoint:
def __init__(self, hash_, n):
self.hash = hash_
self.n = n
def __eq__(self, other):
return self.hash == other.hash and self.n == other.n
def __hash__(self):
return hash((self.hash, self.n))
class FakeCoin:
def __init__(self, txid, index, script, confirmed=True):
self.txid = txid
self.index = index
self.script = script
self.confirmed = confirmed
self.outpoint = FakeOutPoint(txid, index)
def defective_filter(coins, allowed_inputs):
"""Defective: List.Any for AllowedInputs check"""
comps = 0
result = []
for x in coins:
found = False
for y in allowed_inputs:
comps += 1
if y.hash == x.txid and y.n == x.index:
found = True
break
if found:
result.append(x)
return result, comps
def patched_filter(coins, allowed_inputs):
"""Patched: HashSet for AllowedInputs check"""
comps = 0
allowed_set = set(allowed_inputs)
result = []
for x in coins:
comps += 1
if x.outpoint in allowed_set:
result.append(x)
return result, comps
passed = 0
failed = 0
# Test 1: Correctness
coins = [FakeCoin(i, 0, f"script_{i}") for i in range(100)]
allowed = [FakeOutPoint(i * 2, 0) for i in range(50)]
d, _ = defective_filter(coins, allowed)
p, _ = patched_filter(coins, allowed)
if [c.txid for c in d] == [c.txid for c in p] and len(d) == 50:
print("PASS test1_correctness: identical filter results"); passed += 1
else:
print("FAIL test1_correctness"); failed += 1
# Test 2: Performance C=500, A=50
coins = [FakeCoin(i, 0, f"script_{i}") for i in range(500)]
allowed = [FakeOutPoint(i * 10, 0) for i in range(50)]
_, dc = defective_filter(coins, allowed)
_, pc = patched_filter(coins, allowed)
ratio = dc / max(pc, 1)
print(f" C=500 A=50: defective={dc} patched={pc} ratio={ratio:.1f}x")
if ratio > 10.0:
print("PASS test2_perf: >10x fewer comparisons"); passed += 1
else:
print(f"FAIL test2_perf: ratio {ratio:.1f}x not >10x"); failed += 1
# Test 3: Empty allowed returns empty
coins = [FakeCoin(i, 0, f"script_{i}") for i in range(10)]
d, _ = defective_filter(coins, [])
p, _ = patched_filter(coins, [])
if len(d) == 0 and len(p) == 0:
print("PASS test3_empty_allowed: returns empty"); passed += 1
else:
print("FAIL test3_empty_allowed"); failed += 1
# Test 4: All coins allowed
coins = [FakeCoin(i, 0, f"script_{i}") for i in range(20)]
allowed = [c.outpoint for c in coins]
d, _ = defective_filter(coins, allowed)
p, _ = patched_filter(coins, allowed)
if len(d) == 20 and len(p) == 20:
print("PASS test4_all_allowed: all coins pass"); passed += 1
else:
print("FAIL test4_all_allowed"); failed += 1
print(f"\n{passed}/{passed + failed} tests passed")
sys.exit(1 if failed > 0 else 0)