File size: 2,384 Bytes
c05cc7f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
"""Every injected break must be caught, and nothing clean may be flagged.

Run: python -m pytest tests/   (or: python tests/test_engine.py)
"""

import csv
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "recon"))

from engine import load, reconcile  # noqa: E402

EXPECTED_CHECK = {
    "Unbooked capital call": "Capital Call not booked",
    "Distribution misclassified": "Distribution classification",
    "Duplicate transaction": "Duplicate transaction",
    "Valuation lag": ("NAV lag", "Contract value lag"),
    "Rounding": "Rounding",
    "Value break": ("NAV break", "Contract value break"),
    "Commitment mismatch": "Commitment",
    "Stale valuation": "Stale valuation",
    "Unmapped security": "Security mapping",
    "Missing position": "Position setup",
}


def _result():
    data = load(ROOT / "data")
    sm = {s["icapital_id"]: s["name"] for s in data["security_master"]}
    sm.update({s["addepar_id"]: s["name"] for s in data["security_master"] if s["addepar_id"]})
    with open(ROOT / "data" / "injected_breaks.csv") as f:
        injected = [(r["break"], r["account_id"], sm[r["icapital_id"]]) for r in csv.DictReader(f)]
    return reconcile(data), injected


def test_every_injected_break_is_found():
    res, injected = _result()
    found = {(f.check, f.account_id, f.security) for f in res["findings"] if f.status != "Matched"}
    for brk, acct, name in injected:
        want = EXPECTED_CHECK[brk]
        want = want if isinstance(want, tuple) else (want,)
        assert any((w, acct, name) in found for w in want), f"missed {brk} on {acct} {name}"


def test_no_false_positives():
    res, injected = _result()
    flagged = [f for f in res["findings"] if f.status != "Matched"]
    assert len(flagged) == len(injected)


def test_only_reversible_fixes_are_automated():
    res, _ = _result()
    auto_checks = {f.check for f in res["findings"] if f.status == "Auto-resolved"}
    assert not auto_checks & {"Duplicate transaction", "Commitment", "Security mapping", "Position setup"}
    assert {i["action"] for i in res["imports"]} <= {"ADD_TRANSACTION", "RECLASSIFY", "UPDATE_VALUATION"}


if __name__ == "__main__":
    for t in (test_every_injected_break_is_found, test_no_false_positives, test_only_reversible_fixes_are_automated):
        t()
        print("PASS", t.__name__)