ejschwartz commited on
Commit
52a9362
·
1 Parent(s): f09ab97

Add three Faultless completeness examples

Browse files
README.md CHANGED
@@ -13,7 +13,7 @@ fullWidth: true
13
  Public Gradio frontend for comparing a binary function with candidate C. Select
14
  an example or upload an ELF x86-64 binary, supply its function address and candidate
15
  source, and stream verification results with assembly previews and a JSON download.
16
- The application includes 60 examples in expandable sections: Basics, Calls and
17
  memory, Types and ABI, Real binaries, Related work, and Ghidra exports. Each section
18
  has a short description with relevant paper or tool links. Basics starts open;
19
  expand any other section to browse its examples.
@@ -117,9 +117,12 @@ to clone private code before the Docker build. Local developers use the explicit
117
  Startup retains the pinned private core checkout in `core/` after removing its Git
118
  metadata. The UI reads example sources from that checkout and compiles originals
119
  when preparing examples. Local development uses the same loader and submodule.
120
- The Related work section combines six Faultless cases with nine cases from D-Helix,
121
  DiscScope, and Decompile-Diverge, including a deliberately uncompilable export. See `core/docs/related-work-examples.md`
122
  for provenance, interface adaptations, and published counterexamples.
 
 
 
123
  Reference C is a display aid; uploaded binaries have none. DiscScope `orig.c`
124
  excerpts are stored alongside their `raw.c` and `cand.c` in the shared core cases.
125
  They come from binutils 2.29, libsmi 0.4.8, and JasPer 1.900.16, with source
 
13
  Public Gradio frontend for comparing a binary function with candidate C. Select
14
  an example or upload an ELF x86-64 binary, supply its function address and candidate
15
  source, and stream verification results with assembly previews and a JSON download.
16
+ The application includes 63 examples in expandable sections: Basics, Calls and
17
  memory, Types and ABI, Real binaries, Related work, and Ghidra exports. Each section
18
  has a short description with relevant paper or tool links. Basics starts open;
19
  expand any other section to browse its examples.
 
117
  Startup retains the pinned private core checkout in `core/` after removing its Git
118
  metadata. The UI reads example sources from that checkout and compiles originals
119
  when preparing examples. Local development uses the same loader and submodule.
120
+ The Related work section combines nine Faultless cases with nine cases from D-Helix,
121
  DiscScope, and Decompile-Diverge, including a deliberately uncompilable export. See `core/docs/related-work-examples.md`
122
  for provenance, interface adaptations, and published counterexamples.
123
+ The three O0 completeness pairs (`my_putchar_count`, `upper`, and `print_page_header`)
124
+ are stored in `demo/cases/`, including raw exports, source metadata, and documented
125
+ runnable adaptations in [demo/cases/README.md](demo/cases/README.md).
126
  Reference C is a display aid; uploaded binaries have none. DiscScope `orig.c`
127
  excerpts are stored alongside their `raw.c` and `cand.c` in the shared core cases.
128
  They come from binutils 2.29, libsmi 0.4.8, and JasPer 1.900.16, with source
demo/cases/README.md ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Faultless examples
2
+
3
+ Original/decompiled pairs extracted verbatim from the O0 completeness dataset. Decompiled files retain decompiler syntax and are not standalone compilation units.
4
+
5
+ - `my_putchar_count` (Ismuur/Magic): Faultless treats the entire decompiled buffer as involved in write, although write consumes only the first byte (count = 1). Equivalence depends on modeling the callee behavior.
6
+ - `upper` (aaronokano/ecs150-hw1): The decompiled loop exits through an early break; Faultless loop pairing can be brittle around breaks.
7
+ - `print_page_header` (achasse/cse220): The original uses a static local integer, represented as a global in the decompiled code; Faultless has difficulty with static integers.
8
+
9
+ The three directories preserve `original.c`, `decompiled.c`, and `metadata.json`
10
+ from `/tmp/decompile-verify-faultless-examples` unchanged. The metadata records
11
+ the dataset index, canonical function name, source repository, and Faultless's
12
+ reported failure. That failure is distinct from this verifier's result.
13
+
14
+ `candidate.c` is the runnable version. It adds standard headers and removes the
15
+ decompiler's `__fastcall` spelling. `my_putchar_count` restores the original
16
+ 32-bit return type. `upper` restores the original void return and writable
17
+ `char *` parameter, retaining the early break and repeated `strlen` calls.
18
+ `print_page_header` restores the void return while retaining the increment,
19
+ and declares the exported counter as an external integer. The original static
20
+ local remains intact; its `page_number.0` symbol supplies the global binding.
21
+ These examples compare behavior under the original interfaces, including these
22
+ documented corrections to the inferred signatures.
23
+
24
+ `runnable.json` records declarations, original and candidate symbols, callee and
25
+ global bindings, and interfaces. Originals are compiled with GCC at `-O0` and
26
+ `-fno-builtin`. Linker stubs resolve `write`, `strlen`, and `printf`; the verifier
27
+ intercepts them with shared synthetic responses. The stubs do not model libc.
28
+ The `write` interface explicitly compares one byte of its second argument;
29
+ `printf` specifies its four variadic argument types.
30
+
31
+ The one-byte write can remain inconclusive because this verifier requires the
32
+ whole escaped stack frame to agree even with an explicit one-byte range.
33
+ The uppercase loop uses synthetic `strlen` responses, so budget exhaustion is
34
+ possible; it does not demonstrate real libc string handling or loop equivalence.
35
+ Agreement for the page header covers the bound counter and intercepted `printf`
36
+ arguments on tested inputs.
demo/cases/my_putchar_count/candidate.c ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <unistd.h>
2
+
3
+ int func0(char a1)
4
+ {
5
+ char buf[4]; // [rsp+Ch] [rbp-4h] BYREF
6
+
7
+ buf[0] = a1;
8
+ write(1, buf, 1uLL);
9
+ return 1LL;
10
+ }
demo/cases/my_putchar_count/decompiled.c ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ __int64 __fastcall func0(char a1)
2
+ {
3
+ char buf[4]; // [rsp+Ch] [rbp-4h] BYREF
4
+
5
+ buf[0] = a1;
6
+ write(1, buf, 1uLL);
7
+ return 1LL;
8
+ }
demo/cases/my_putchar_count/metadata.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "repo": "Ismuur/Magic",
3
+ "name": "my_putchar_count",
4
+ "index": 74,
5
+ "canonical_name": "func0",
6
+ "status": "failure",
7
+ "nonequivalence_reason": "Function write in the original function has no equivalent in the decompiled function.",
8
+ "source_report": "O0_opt_parity_test/report.md",
9
+ "note": "Faultless treats the entire decompiled buffer as involved in write, although write consumes only the first byte (count = 1). Equivalence depends on modeling the callee behavior."
10
+ }
demo/cases/my_putchar_count/original.c ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ int my_putchar_count(char c)
2
+ {
3
+ write(1, &c, 1);
4
+ return (1);
5
+ }
demo/cases/my_putchar_count/runnable.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "original_symbol": "my_putchar_count",
3
+ "candidate_symbol": "func0",
4
+ "declarations": "#include <unistd.h>\n",
5
+ "stubs": "#include <unistd.h>\nssize_t write(int fd, const void *buffer, size_t count) { return 0; }\n",
6
+ "callees": {
7
+ "write": "write"
8
+ },
9
+ "interfaces": {
10
+ "original_prototype": "int my_putchar_count(char c);",
11
+ "memory_ranges": {
12
+ "write": {
13
+ "1": 1
14
+ }
15
+ }
16
+ }
17
+ }
demo/cases/print_page_header/candidate.c ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ #include <stdio.h>
2
+ extern int page_number_0;
3
+
4
+ void func9(const char *a1, const char *a2)
5
+ {
6
+ printf("Page %3d %*s\t %s\t \n", (unsigned int)page_number_0, 26, a1, a2);
7
+ ++page_number_0;
8
+ }
demo/cases/print_page_header/decompiled.c ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ __int64 __fastcall func9(const char *a1, const char *a2)
2
+ {
3
+ printf("Page %3d %*s\t %s\t \n", (unsigned int)page_number_0, 26, a1, a2);
4
+ return (unsigned int)++page_number_0;
5
+ }
demo/cases/print_page_header/metadata.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "repo": "achasse/cse220",
3
+ "name": "print_page_header",
4
+ "index": 194,
5
+ "canonical_name": "func9",
6
+ "status": "failure",
7
+ "nonequivalence_reason": "Function printf in the original function has no equivalent in the decompiled function.",
8
+ "source_report": "O0_opt_parity_test/report.md",
9
+ "note": "The original uses a static local integer, represented as a global in the decompiled code; Faultless has difficulty with static integers."
10
+ }
demo/cases/print_page_header/original.c ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ static void print_page_header(char source_name[], char date[])
2
+ {
3
+ static int page_number = 0;
4
+ printf("Page %3d %*s\t %s\t \n", page_number, 80/3, source_name, date);
5
+ page_number++;
6
+ }
demo/cases/print_page_header/runnable.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "original_symbol": "print_page_header",
3
+ "candidate_symbol": "func9",
4
+ "declarations": "#include <stdio.h>\n",
5
+ "stubs": "int printf(const char *format, ...) { return 0; }\n",
6
+ "callees": {
7
+ "printf": "printf"
8
+ },
9
+ "globals": {
10
+ "page_number_0": "page_number.0"
11
+ },
12
+ "interfaces": {
13
+ "original_prototype": "void print_page_header(char *source_name, char *date);",
14
+ "callee_interfaces": {
15
+ "printf": {
16
+ "variadic_types": [
17
+ "int",
18
+ "int",
19
+ "char *",
20
+ "char *"
21
+ ]
22
+ }
23
+ }
24
+ }
25
+ }
demo/cases/upper/candidate.c ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <string.h>
2
+
3
+ void func8(char *a1)
4
+ {
5
+ size_t result; // rax
6
+ int i; // [rsp+1Ch] [rbp-14h]
7
+
8
+ for ( i = 0; ; ++i )
9
+ {
10
+ result = strlen(a1);
11
+ if ( i >= result )
12
+ break;
13
+ if ( a1[i] > 96 && a1[i] <= 122 )
14
+ a1[i] -= 32;
15
+ }
16
+ return;
17
+ }
demo/cases/upper/decompiled.c ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ size_t __fastcall func8(const char *a1)
2
+ {
3
+ size_t result; // rax
4
+ int i; // [rsp+1Ch] [rbp-14h]
5
+
6
+ for ( i = 0; ; ++i )
7
+ {
8
+ result = strlen(a1);
9
+ if ( i >= result )
10
+ break;
11
+ if ( a1[i] > 96 && a1[i] <= 122 )
12
+ a1[i] -= 32;
13
+ }
14
+ return result;
15
+ }
demo/cases/upper/metadata.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "repo": "aaronokano/ecs150-hw1",
3
+ "name": "upper",
4
+ "index": 188,
5
+ "canonical_name": "func8",
6
+ "status": "failure",
7
+ "nonequivalence_reason": "Function strlen in the original function has no equivalent in the decompiled function.",
8
+ "source_report": "O0_opt_parity_test/report.md",
9
+ "note": "The decompiled loop exits through an early break; Faultless loop pairing can be brittle around breaks."
10
+ }
demo/cases/upper/original.c ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ void upper(char *mystring) {
2
+ int i; int diff = 'a' - 'A';
3
+ for( i = 0; i < strlen( mystring ); i++ ) {
4
+ if( mystring[i] >= 'a' && mystring[i] <= 'z' )
5
+ mystring[i] -= diff;
6
+ }
7
+ }
demo/cases/upper/runnable.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "original_symbol": "upper",
3
+ "candidate_symbol": "func8",
4
+ "declarations": "#include <string.h>\n",
5
+ "stubs": "#include <stddef.h>\nsize_t strlen(const char *s) { return 0; }\n",
6
+ "callees": {
7
+ "strlen": "strlen"
8
+ },
9
+ "interfaces": {
10
+ "original_prototype": "void upper(char *mystring);"
11
+ }
12
+ }
demo/examples.py CHANGED
@@ -1,4 +1,4 @@
1
- """Use the same example sources and preparation as the core tests."""
2
  from pathlib import Path
3
  import sys
4
  import json
@@ -6,13 +6,21 @@ import json
6
  ROOT = Path(__file__).resolve().parents[1]
7
  sys.path.insert(0, str(ROOT / "core"))
8
 
9
- from examples.ui import (EXAMPLE_NAMES, EXAMPLE_LABELS, ORIGINAL_EXAMPLE_NAMES,
10
- ORIGINAL_EXAMPLE_LABELS, GHIDRA_EXAMPLE_NAMES,
11
- ghidra_metadata)
12
  from examples import ui as core_examples
 
 
 
 
 
 
 
 
13
 
14
 
15
  def example_metadata(name):
 
 
16
  metadata = core_examples.example_metadata(name)
17
  if name == "faultless-linked-list":
18
  metadata["expected_verdict"] = "mismatch"
@@ -34,6 +42,7 @@ def expected_result(name, compiler="gcc"):
34
 
35
  def prepare_examples(directory, *, include_ghidra=True):
36
  rows = dict(zip(core_examples.EXAMPLE_NAMES, core_examples.prepare_examples(directory)))
 
37
  names = EXAMPLE_NAMES if include_ghidra else tuple(
38
  name for name in EXAMPLE_NAMES if name not in GHIDRA_EXAMPLE_NAMES)
39
  selected = [rows[name] for name in names]
@@ -50,7 +59,7 @@ EXAMPLE_GROUPS = (
50
  ("Types and ABI", ("wide-integer", "float-identity", "signed-zero", "nan-payload",
51
  "struct-fields", "struct-indirect", "struct-padding", "pointer-identity")),
52
  ("Real binaries", ("factor-gcd", "factor-gcd-euclidean", "factor-gcd-even")),
53
- ("Related work", core_examples.FAULTLESS_NAMES + core_examples.RESEARCH_NAMES),
54
  ("Ghidra exports", GHIDRA_EXAMPLE_NAMES),
55
  )
56
 
 
1
+ """Combine shared core examples with saved frontend completeness pairs."""
2
  from pathlib import Path
3
  import sys
4
  import json
 
6
  ROOT = Path(__file__).resolve().parents[1]
7
  sys.path.insert(0, str(ROOT / "core"))
8
 
9
+ from examples.ui import GHIDRA_EXAMPLE_NAMES, ghidra_metadata
 
 
10
  from examples import ui as core_examples
11
+ from demo import faultless
12
+
13
+ ORIGINAL_EXAMPLE_NAMES = core_examples.ORIGINAL_EXAMPLE_NAMES + faultless.NAMES
14
+ ORIGINAL_EXAMPLE_LABELS = core_examples.ORIGINAL_EXAMPLE_LABELS + faultless.LABELS
15
+ EXAMPLE_NAMES = ORIGINAL_EXAMPLE_NAMES + GHIDRA_EXAMPLE_NAMES
16
+ EXAMPLE_LABELS = ORIGINAL_EXAMPLE_LABELS + tuple(
17
+ core_examples.EXAMPLE_LABELS[core_examples.EXAMPLE_NAMES.index(name)]
18
+ for name in GHIDRA_EXAMPLE_NAMES)
19
 
20
 
21
  def example_metadata(name):
22
+ if name in faultless.NAMES:
23
+ return faultless.metadata(name)
24
  metadata = core_examples.example_metadata(name)
25
  if name == "faultless-linked-list":
26
  metadata["expected_verdict"] = "mismatch"
 
42
 
43
  def prepare_examples(directory, *, include_ghidra=True):
44
  rows = dict(zip(core_examples.EXAMPLE_NAMES, core_examples.prepare_examples(directory)))
45
+ rows.update(zip(faultless.NAMES, faultless.prepare_examples(directory)))
46
  names = EXAMPLE_NAMES if include_ghidra else tuple(
47
  name for name in EXAMPLE_NAMES if name not in GHIDRA_EXAMPLE_NAMES)
48
  selected = [rows[name] for name in names]
 
59
  ("Types and ABI", ("wide-integer", "float-identity", "signed-zero", "nan-payload",
60
  "struct-fields", "struct-indirect", "struct-padding", "pointer-identity")),
61
  ("Real binaries", ("factor-gcd", "factor-gcd-euclidean", "factor-gcd-even")),
62
+ ("Related work", core_examples.FAULTLESS_NAMES + core_examples.RESEARCH_NAMES + faultless.NAMES),
63
  ("Ghidra exports", GHIDRA_EXAMPLE_NAMES),
64
  )
65
 
demo/faultless.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Saved O0 completeness pairs, with explicit runnable interface adaptations."""
2
+ import json
3
+ from pathlib import Path
4
+ import subprocess
5
+ import tempfile
6
+
7
+ import cle
8
+ import yaml
9
+
10
+
11
+ CASES = Path(__file__).with_name("cases")
12
+ NAMES = ("faultless-my-putchar-count", "faultless-upper", "faultless-print-page-header")
13
+ CASE_NAMES = ("my_putchar_count", "upper", "print_page_header")
14
+ LABELS = ("Faultless: One-byte write", "Faultless: Uppercase loop",
15
+ "Faultless: Static page counter")
16
+
17
+
18
+ def source(name, filename):
19
+ return (CASES / CASE_NAMES[NAMES.index(name)] / filename).read_text()
20
+
21
+
22
+ def metadata(name):
23
+ info = json.loads(source(name, "metadata.json"))
24
+ info.update(reference=source(name, "original.c"),
25
+ expected_verdict="inconclusive" if name == NAMES[0] else "agree")
26
+ return info
27
+
28
+
29
+ def prepare_examples(directory):
30
+ output = Path(directory).resolve()
31
+ output.mkdir(parents=True, exist_ok=True)
32
+ rows = []
33
+ with tempfile.TemporaryDirectory(prefix="faultless-completeness-") as temporary:
34
+ temporary = Path(temporary)
35
+ for name in NAMES:
36
+ case = CASES / CASE_NAMES[NAMES.index(name)]
37
+ info = json.loads((case / "runnable.json").read_text())
38
+ original = temporary / "original.c"
39
+ original.write_text(info["declarations"] + source(name, "original.c"))
40
+ stubs = temporary / "callees.c"
41
+ stubs.write_text(info["stubs"])
42
+ binary = output / (name + ".elf")
43
+ flags = ["-O0", "-fno-builtin"]
44
+ subprocess.run(["gcc", *flags, "-fno-pie", "-no-pie", "-fno-stack-protector",
45
+ "-nostdlib", "-Wl,--build-id=none", "-Wl,-e," + info["original_symbol"],
46
+ str(original), str(stubs), "-o", str(binary)],
47
+ check=True, capture_output=True, text=True, timeout=60)
48
+ obj = cle.Loader(str(binary), auto_load_libs=False).main_object
49
+ addresses = {symbol.name: symbol.rebased_addr for symbol in obj.symbols
50
+ if not symbol.is_import}
51
+ bindings = {kind: {candidate: addresses[original] for candidate, original in
52
+ info.get(kind, {}).items()} for kind in ("callees", "globals")}
53
+ rows.append([str(binary), f"{addresses[info['original_symbol']]:#x}",
54
+ (case / "candidate.c").read_text(), yaml.safe_dump(bindings, sort_keys=True),
55
+ info["candidate_symbol"], 100, "0", 1000, "gcc", " ".join(flags),
56
+ yaml.safe_dump(info["interfaces"], sort_keys=True)])
57
+ return rows
tests/test_examples.py CHANGED
@@ -5,7 +5,7 @@ from demo import examples
5
 
6
  def test_examples_prepare_from_core_checkout(tmp_path):
7
  rows = examples.prepare_examples(tmp_path)
8
- assert len(rows) == len(examples.EXAMPLE_NAMES) == 60
9
  assert len(examples.GHIDRA_EXAMPLE_NAMES) == 21
10
  assert all(Path(row[0]).is_file() for row in rows)
11
  assert all(Path(row[0]).is_relative_to(tmp_path) for row in rows)
@@ -18,7 +18,7 @@ def test_example_groups_cover_catalog_once():
18
  assert len(members) == len(set(members)) == len(examples.EXAMPLE_NAMES)
19
  assert set(members) == set(examples.EXAMPLE_NAMES)
20
  groups = examples.example_groups(examples.EXAMPLE_NAMES)
21
- assert [len(indices) for _, indices in groups] == [6, 7, 8, 3, 15, 21]
22
  for _, indices in groups:
23
  assert list(indices) == sorted(indices)
24
 
 
5
 
6
  def test_examples_prepare_from_core_checkout(tmp_path):
7
  rows = examples.prepare_examples(tmp_path)
8
+ assert len(rows) == len(examples.EXAMPLE_NAMES) == 63
9
  assert len(examples.GHIDRA_EXAMPLE_NAMES) == 21
10
  assert all(Path(row[0]).is_file() for row in rows)
11
  assert all(Path(row[0]).is_relative_to(tmp_path) for row in rows)
 
18
  assert len(members) == len(set(members)) == len(examples.EXAMPLE_NAMES)
19
  assert set(members) == set(examples.EXAMPLE_NAMES)
20
  groups = examples.example_groups(examples.EXAMPLE_NAMES)
21
+ assert [len(indices) for _, indices in groups] == [6, 7, 8, 3, 18, 21]
22
  for _, indices in groups:
23
  assert list(indices) == sorted(indices)
24
 
tests/test_faultless.py CHANGED
@@ -5,6 +5,7 @@ import pytest
5
 
6
  from demo.app import run_verification
7
  from demo.examples import EXAMPLE_NAMES, example_metadata
 
8
 
9
 
10
  @pytest.mark.parametrize('compiler', ['gcc', 'clang'])
@@ -37,6 +38,10 @@ def test_faultless_frontend_stream(tmp_path, compiler, name, example_rows):
37
  assert report['counts']['agree'] == seed_count
38
  elif name == 'faultless-byte-reinterpretation':
39
  assert report['counts'][expected] == seed_count
 
 
 
 
40
  else:
41
  assert report['counts']['mismatch'] == seed_count
42
  assert all(r['divergence'] == 'call[0]' for r in report['results'])
 
5
 
6
  from demo.app import run_verification
7
  from demo.examples import EXAMPLE_NAMES, example_metadata
8
+ from demo.faultless import NAMES as COMPLETENESS_NAMES
9
 
10
 
11
  @pytest.mark.parametrize('compiler', ['gcc', 'clang'])
 
38
  assert report['counts']['agree'] == seed_count
39
  elif name == 'faultless-byte-reinterpretation':
40
  assert report['counts'][expected] == seed_count
41
+ elif name in COMPLETENESS_NAMES:
42
+ assert report['counts'][expected] == seed_count
43
+ if name == 'faultless-my-putchar-count':
44
+ assert all(r['reason'] == 'escaped_frame_differs' for r in report['results'])
45
  else:
46
  assert report['counts']['mismatch'] == seed_count
47
  assert all(r['divergence'] == 'call[0]' for r in report['results'])
tests/test_ui.py CHANGED
@@ -10,6 +10,7 @@ from urllib.parse import quote
10
 
11
  from demo.examples import (EXAMPLE_NAMES, EXAMPLE_LABELS, ORIGINAL_EXAMPLE_NAMES,
12
  GHIDRA_EXAMPLE_NAMES, ROOT, ghidra_metadata)
 
13
  from demo.presentation import json_detail, mismatch_summary
14
  from tests.support import check_report
15
 
@@ -102,8 +103,8 @@ def test_example_reference_pane_events(tmp_path):
102
  app.close()
103
 
104
 
105
- @pytest.mark.parametrize("names", [ORIGINAL_EXAMPLE_NAMES, GHIDRA_EXAMPLE_NAMES],
106
- ids=["original", "ghidra"])
107
  def test_queued_ui_upload_streaming_and_download(tmp_path, monkeypatch, names):
108
  from gradio_client import Client, handle_file
109
  from gradio_client.exceptions import AppError
 
10
 
11
  from demo.examples import (EXAMPLE_NAMES, EXAMPLE_LABELS, ORIGINAL_EXAMPLE_NAMES,
12
  GHIDRA_EXAMPLE_NAMES, ROOT, ghidra_metadata)
13
+ from demo.faultless import NAMES as COMPLETENESS_NAMES
14
  from demo.presentation import json_detail, mismatch_summary
15
  from tests.support import check_report
16
 
 
103
  app.close()
104
 
105
 
106
+ @pytest.mark.parametrize("names", [ORIGINAL_EXAMPLE_NAMES, GHIDRA_EXAMPLE_NAMES, COMPLETENESS_NAMES],
107
+ ids=["original", "ghidra", "faultless-completeness"])
108
  def test_queued_ui_upload_streaming_and_download(tmp_path, monkeypatch, names):
109
  from gradio_client import Client, handle_file
110
  from gradio_client.exceptions import AppError