diff --git a/decbench/models/decompilation.py b/decbench/models/decompilation.py index c9b1221..fe8faa4 100644 --- a/decbench/models/decompilation.py +++ b/decbench/models/decompilation.py @@ -145,7 +145,12 @@ def function_count(self) -> int: @property def successful_count(self) -> int: - return len(self.functions) - len(self.decompiler.failed_functions) + """Count returned function bodies that are nonempty and not marked failed.""" + failed = set(self.decompiler.failed_functions) - {"all"} + return sum( + bool(function.decompiled_code.strip()) and key not in failed + for key, function in self.functions.items() + ) def to_c_file(self, path: Path) -> None: """Write combined decompilation to a C file.""" diff --git a/tests/test_models.py b/tests/test_models.py index 2d8180a..fe39c17 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -138,6 +138,26 @@ def test_decompilation_result(self) -> None: assert result.function_count == 1 assert result.successful_count == 1 + @pytest.mark.parametrize( + "failed", [["missing1", "missing2", "failed"], ["all", "missing1", "missing2", "failed"]] + ) + def test_success_count_only_counts_returned_usable_results(self, failed: list[str]) -> None: + result = DecompilationResult( + binary_path=Path("binary"), + binary_name="binary", + decompiler=DecompilerMetadata(decompiler_name="test_dec", failed_functions=failed), + functions={ + "good": FunctionDecompilation( + name="good", address=0x1000, decompiled_code="int good() { return 1; }" + ), + "failed": FunctionDecompilation( + name="failed", address=0x2000, decompiled_code="incomplete" + ), + "empty": FunctionDecompilation(name="empty", address=0x3000, decompiled_code=" \n"), + }, + ) + assert result.successful_count == 1 + def test_legacy_function_toml_without_cost_fields(self, tmp_path: Path) -> None: function = FunctionDecompilation( name="main", address=0x1000, decompiled_code="int main() {}"