Torres1980 commited on
Commit
c05cc7f
·
verified ·
1 Parent(s): 1a85018

Add engine tests

Browse files
Files changed (1) hide show
  1. tests/test_engine.py +63 -0
tests/test_engine.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Every injected break must be caught, and nothing clean may be flagged.
2
+
3
+ Run: python -m pytest tests/ (or: python tests/test_engine.py)
4
+ """
5
+
6
+ import csv
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ ROOT = Path(__file__).resolve().parent.parent
11
+ sys.path.insert(0, str(ROOT / "recon"))
12
+
13
+ from engine import load, reconcile # noqa: E402
14
+
15
+ EXPECTED_CHECK = {
16
+ "Unbooked capital call": "Capital Call not booked",
17
+ "Distribution misclassified": "Distribution classification",
18
+ "Duplicate transaction": "Duplicate transaction",
19
+ "Valuation lag": ("NAV lag", "Contract value lag"),
20
+ "Rounding": "Rounding",
21
+ "Value break": ("NAV break", "Contract value break"),
22
+ "Commitment mismatch": "Commitment",
23
+ "Stale valuation": "Stale valuation",
24
+ "Unmapped security": "Security mapping",
25
+ "Missing position": "Position setup",
26
+ }
27
+
28
+
29
+ def _result():
30
+ data = load(ROOT / "data")
31
+ sm = {s["icapital_id"]: s["name"] for s in data["security_master"]}
32
+ sm.update({s["addepar_id"]: s["name"] for s in data["security_master"] if s["addepar_id"]})
33
+ with open(ROOT / "data" / "injected_breaks.csv") as f:
34
+ injected = [(r["break"], r["account_id"], sm[r["icapital_id"]]) for r in csv.DictReader(f)]
35
+ return reconcile(data), injected
36
+
37
+
38
+ def test_every_injected_break_is_found():
39
+ res, injected = _result()
40
+ found = {(f.check, f.account_id, f.security) for f in res["findings"] if f.status != "Matched"}
41
+ for brk, acct, name in injected:
42
+ want = EXPECTED_CHECK[brk]
43
+ want = want if isinstance(want, tuple) else (want,)
44
+ assert any((w, acct, name) in found for w in want), f"missed {brk} on {acct} {name}"
45
+
46
+
47
+ def test_no_false_positives():
48
+ res, injected = _result()
49
+ flagged = [f for f in res["findings"] if f.status != "Matched"]
50
+ assert len(flagged) == len(injected)
51
+
52
+
53
+ def test_only_reversible_fixes_are_automated():
54
+ res, _ = _result()
55
+ auto_checks = {f.check for f in res["findings"] if f.status == "Auto-resolved"}
56
+ assert not auto_checks & {"Duplicate transaction", "Commitment", "Security mapping", "Position setup"}
57
+ assert {i["action"] for i in res["imports"]} <= {"ADD_TRANSACTION", "RECLASSIFY", "UPDATE_VALUATION"}
58
+
59
+
60
+ if __name__ == "__main__":
61
+ for t in (test_every_injected_break_is_found, test_no_false_positives, test_only_reversible_fixes_are_automated):
62
+ t()
63
+ print("PASS", t.__name__)