|
58 | 58 | 'ton', |
59 | 59 | ]), |
60 | 60 | 'Z': ('Zcash', '#F4B728', [ |
61 | | - 'zcash', 'signtx_zcash', |
| 61 | + 'zcash', 'signtx_zcash', 'zcash_orchard', 'zcash_sign_pczt', |
| 62 | + 'zcash_nu6', 'zcash_v5', 'zcash_complete', |
62 | 63 | ]), |
63 | 64 | 'R': ('Ripple (XRP)', '#23292F', [ |
64 | 65 | 'ripple', |
@@ -167,12 +168,56 @@ def img_to_data_uri(path): |
167 | 168 | return f'data:image/png;base64,{base64.b64encode(f.read()).decode()}' |
168 | 169 |
|
169 | 170 |
|
170 | | -def is_blank(path): |
171 | | - """Check if screenshot is mostly blank (< 50 white pixels).""" |
| 171 | +# Hash-based dedup: track how many tests contain each frame hash. |
| 172 | +# Frames that appear in 10+ distinct tests are setUp noise (splash/recovery). |
| 173 | +_SEEN_HASHES: dict = {} |
| 174 | +_SETUP_HASHES: set = set() |
| 175 | + |
| 176 | + |
| 177 | +def _img_hash(data: bytes) -> str: |
| 178 | + import hashlib |
| 179 | + return hashlib.md5(data).hexdigest() |
| 180 | + |
| 181 | + |
| 182 | +def is_blank_or_setup(path): |
| 183 | + """Filter out blank screens, setUp noise, and duplicate splash frames. |
| 184 | +
|
| 185 | + Filtered: |
| 186 | + - Nearly-blank frames (< 3% lit pixels) |
| 187 | + - KeepKey logo splash / recovery import screens (appear 10+ times across |
| 188 | + tests, identified by hash-based cross-test dedup — bug #11/#16) |
| 189 | + """ |
172 | 190 | try: |
173 | 191 | data = open(path, 'rb').read() |
174 | | - return len(data) < 400 |
175 | | - except: |
| 192 | + if len(data) < 400: |
| 193 | + return True |
| 194 | + |
| 195 | + h = _img_hash(data) |
| 196 | + if h in _SETUP_HASHES: |
| 197 | + return True |
| 198 | + |
| 199 | + try: |
| 200 | + from PIL import Image |
| 201 | + import io |
| 202 | + im = Image.open(io.BytesIO(data)) |
| 203 | + if im.size != (256, 64): |
| 204 | + return False |
| 205 | + pixels = list(im.getdata()) |
| 206 | + lit = sum(1 for p in pixels if (p[0] + p[1] + p[2]) > 30) |
| 207 | + total = 256 * 64 |
| 208 | + if lit < total * 0.03: |
| 209 | + _SETUP_HASHES.add(h) |
| 210 | + return True |
| 211 | + # Cross-test dedup: frames seen in 10+ tests are setUp screens |
| 212 | + count = _SEEN_HASHES.get(h, 0) + 1 |
| 213 | + _SEEN_HASHES[h] = count |
| 214 | + if count >= 10: |
| 215 | + _SETUP_HASHES.add(h) |
| 216 | + return True |
| 217 | + except ImportError: |
| 218 | + pass |
| 219 | + return False |
| 220 | + except Exception: |
176 | 221 | return True |
177 | 222 |
|
178 | 223 |
|
@@ -289,8 +334,11 @@ def generate_html(screenshots, junit_results, output_path): |
289 | 334 | status_class = 'pass' if result == 'PASS' else 'fail' if result in ('FAIL', 'ERROR') else '' |
290 | 335 | badge_class = 'pass' if result == 'PASS' else 'fail' if result in ('FAIL', 'ERROR') else 'skip' |
291 | 336 |
|
292 | | - # Filter out blank screens for cleaner display |
293 | | - interesting = [(i, p) for i, p in enumerate(pngs) if not is_blank(p)] |
| 337 | + # Filter out blank/setUp screens; cap Bitcoin at 8 frames |
| 338 | + # to prevent BTC signtx tests from dominating the report (bug #18) |
| 339 | + interesting = [(i, p) for i, p in enumerate(pngs) if not is_blank_or_setup(p)] |
| 340 | + if letter == 'B' and len(interesting) > 8: |
| 341 | + interesting = interesting[:8] |
294 | 342 |
|
295 | 343 | html.append(f""" |
296 | 344 | <div class="test-card {status_class}"> |
|
0 commit comments