Skip to content

Commit b68984e

Browse files
tests: consolidate feature test fixtures and runners
1 parent ad6aeb0 commit b68984e

19 files changed

Lines changed: 2632 additions & 1148 deletions

tests/fixtures.py

Lines changed: 555 additions & 177 deletions
Large diffs are not rendered by default.

tests/fixtures/features/README.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# backend feature fixtures
2+
3+
This spec describes how contributors should add and consume backend feature fixtures.
4+
5+
## Scope
6+
7+
This spec covers feature-fixture tests only. It does not cover extractor helper tests, CLI smoke tests, or other bespoke tests.
8+
9+
## Source of truth
10+
11+
Feature fixtures live in these JSON manifests under `tests/fixtures/features/`:
12+
13+
- `static.json`
14+
- `binja-db.json`
15+
- `binexport.json`
16+
- `cape.json`
17+
- `drakvuf.json`
18+
- `vmray.json`
19+
20+
Each manifest contains:
21+
22+
- a `files` list that maps fixture keys to sample paths
23+
- a `features` list that describes feature assertions
24+
25+
The loader reads all of these manifests and combines them into one fixture set.
26+
27+
A backend feature test should not maintain its own private list of feature fixtures if the same information can be expressed in these JSON manifests.
28+
29+
## Fixture shape
30+
31+
Each feature fixture specifies:
32+
33+
- the sample key
34+
- the location within the sample
35+
- the feature or statement to evaluate
36+
- optional tags
37+
- optional backend marks
38+
- optional `expected: false`
39+
40+
If `expected` is omitted, it means `true`.
41+
42+
This applies to ordinary feature assertions and `count(...)` assertions.
43+
44+
Examples:
45+
46+
```json
47+
{
48+
"file": "pma16-01",
49+
"location": "file",
50+
"feature": "format: pe"
51+
}
52+
```
53+
54+
```json
55+
{
56+
"file": "mimikatz",
57+
"location": "function=0x40E5C2",
58+
"feature": "count(basic blocks): 7"
59+
}
60+
```
61+
62+
```json
63+
{
64+
"file": "mimikatz",
65+
"location": "function=0x401000",
66+
"feature": "characteristic: loop",
67+
"expected": false
68+
}
69+
```
70+
71+
## Tags
72+
73+
Tags are used to describe fixture requirements or sample properties that backends may need for selection.
74+
75+
Examples include:
76+
77+
- `dotnet`
78+
- `elf`
79+
- `dynamic`
80+
- `flirt`
81+
- `symtab`
82+
- `binja-db`
83+
- `binexport`
84+
- `aarch64`
85+
86+
Tags may appear on file entries or feature entries. file tags are inherited by their features.
87+
88+
Tags should not duplicate information that can already be derived from:
89+
90+
- the location string
91+
- the parsed feature type
92+
93+
Unknown tags should fail collection.
94+
95+
## Backend selection
96+
97+
Backends consume one shared fixture list and select the fixtures they support.
98+
99+
Large backends should prefer exclusion-based selection. this means new fixtures run by default unless they are explicitly out of scope.
100+
101+
Examples:
102+
103+
- `viv` excludes `.NET`
104+
- `ghidra` excludes `.NET`
105+
- `binja` excludes `.NET`
106+
- `idalib` excludes `.NET`
107+
108+
Small-surface backends may use inclusion-based selection where that is clearer.
109+
110+
Examples:
111+
112+
- `dnfile` includes `.NET`
113+
- `dotnetfile` includes `.NET`
114+
115+
Backends may also restrict supported scopes or feature types.
116+
117+
## Backend test file shape
118+
119+
A backend feature test file should normally have:
120+
121+
- one backend policy object
122+
- one feature-test entry point that consumes shared fixtures
123+
124+
For example:
125+
126+
```python
127+
import fixtures
128+
129+
BACKEND = fixtures.BackendFeaturePolicy(
130+
name="viv",
131+
get_extractor=fixtures.get_viv_extractor,
132+
exclude_tags={"dotnet"},
133+
)
134+
135+
136+
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
137+
def test_viv_features(feature_fixture):
138+
fixtures.run_feature_fixture(BACKEND, feature_fixture)
139+
```
140+
141+
Module-level availability checks are still allowed. runtime-specific hooks are allowed only when they depend on the installed backend or tool version and cannot be represented declaratively in the fixture manifests.
142+
143+
## Known bugs and marks
144+
145+
Known backend bugs should be represented in the fixture manifests through backend-specific marks.
146+
147+
Backends should not usually edit the shared JSON manifests just to avoid a fixture. they should prefer selecting or excluding fixtures through backend policy.
148+
149+
The main reason to keep marks in JSON is to record known exceptions such as:
150+
151+
- a backend-specific `xfail`
152+
- a backend-specific `skip`
153+
154+
## Expected contributor workflow
155+
156+
When adding a new feature test:
157+
158+
1. add the sample path to the appropriate JSON manifest `files` list if it is not already present
159+
2. add the feature fixture to that manifest `features` list
160+
3. add tags only when they express a real requirement or sample property
161+
4. omit `expected` unless the expected result is `false`
162+
5. use JSON marks only for known backend bugs
163+
164+
When adding a new backend:
165+
166+
1. create one backend feature test file
167+
2. define one backend policy describing extractor and exclusions
168+
3. use the shared feature runner
169+
4. add runtime hooks only if the environment or installed tool version requires them

0 commit comments

Comments
 (0)