File size: 5,391 Bytes
e23172f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""Mock FormFav responses for tests — no live API needed.

Includes realistic race forms (matching the observed FormFav shape) and
designed edge cases: scratched runners, abandoned races, missing fields,
x/spell form strings, and incomplete data.
"""
from __future__ import annotations

from pathlib import Path


def meetings_payload(date: str = "2026-08-11") -> dict:
    return {
        "date": date,
        "raceType": "gallops",
        "meetings": [
            {"track": "Dubbo", "slug": "dubbo", "country": "au", "abandoned": False,
             "races": [{"raceNumber": 1}, {"raceNumber": 2}]},
            {"track": "Randwick", "slug": "randwick", "country": "au", "abandoned": False,
             "races": [{"raceNumber": 7}]},
            # non-AU meeting (must be filtered out)
            {"track": "Riccarton", "slug": "riccarton", "country": "nz", "abandoned": False,
             "races": [{"raceNumber": 1}]},
        ],
    }


def race_form_full(date: str = "2026-08-11", track: str = "dubbo", race: int = 1) -> dict:
    return {
        "date": date, "track": track, "raceNumber": race, "raceName": "Maiden Plate",
        "distance": "1200m", "condition": "Good 4", "weather": "Fine", "raceClass": "MDN",
        "abandoned": False, "startTime": "2026-08-11T03:25:00Z", "timezone": "Australia/Sydney",
        "prizeMoney": "30000", "numberOfRunners": 3, "trackSlug": track,
        "runners": [
            {"number": 1, "name": "Speedy", "jockey": "J. Doe", "trainer": "A. Smith",
             "weight": 57.0, "barrier": 2, "age": 4, "sex": "Gelding",
             "careerPrizeMoney": "$25000", "form": "1x231", "last20Starts": "1x231",
             "scratched": False,
             "stats": {"overall": {"starts": 5, "wins": 1, "places": 3, "seconds": 1,
                                   "thirds": 1, "winPercent": 20.0, "placePercent": 60.0},
                       "track": {"starts": 2, "places": 1},
                       "distance": {"starts": 1, "places": 1},
                       "conditions": {"good": {"starts": 3, "places": 2}}}},
            {"number": 2, "name": "Stayer", "jockey": "K. Lee", "trainer": "B. Cole",
             "weight": 58.5, "barrier": 7, "age": 5, "sex": "Mare",
             "careerPrizeMoney": "$10000", "form": "45340", "last20Starts": "45340",
             "scratched": False,
             "stats": {"overall": {"starts": 4, "wins": 0, "places": 1, "seconds": 0,
                                   "thirds": 1, "winPercent": 0.0, "placePercent": 25.0},
                       "track": {"starts": 1, "places": 0},
                       "distance": {"starts": 2, "places": 0},
                       "conditions": {"good": {"starts": 2, "places": 1}}}},
            {"number": 3, "name": "Sprinter", "jockey": "M. Ray", "trainer": "C. Vu",
             "weight": 55.0, "barrier": 1, "age": 3, "sex": "Filly",
             "careerPrizeMoney": "$5000", "form": "22211", "last20Starts": "22211",
             "scratched": False,
             "stats": {"overall": {"starts": 6, "wins": 2, "places": 4, "seconds": 2,
                                   "thirds": 0, "winPercent": 33.3, "placePercent": 66.6},
                       "track": {"starts": 1, "places": 1},
                       "distance": {"starts": 2, "places": 2},
                       "conditions": {"good": {"starts": 3, "places": 2}}}},
        ],
    }


def race_form_with_scratch_and_missing(date: str = "2026-08-11", track: str = "randwick", race: int = 7) -> dict:
    return {
        "date": date, "track": track, "raceNumber": race, "raceName": "Group 1 Sprint",
        "distance": "1600m", "condition": "Soft 5", "raceClass": "G1",
        "abandoned": False, "startTime": "2026-08-11T05:00:00Z", "timezone": "Australia/Sydney",
        "numberOfRunners": 2, "trackSlug": track,
        "runners": [
            {"number": 4, "name": "NoForm", "jockey": "J. X", "trainer": "T. Y",
             "weight": 59.0, "barrier": 9,
             # no 'form' field (falls back to last20Starts)
             "last20Starts": "7777x",
             "scratched": True,  # scratched — must be excluded
             "stats": {"overall": {"starts": 1, "wins": 0, "places": 0,
                                   "winPercent": 0.0, "placePercent": 0.0}}},
            {"number": 8, "name": "OnlyOne", "jockey": "K. Z", "trainer": "L. W",
             "weight": 56.0, "barrier": 3, "age": 4, "sex": "Gelding",
             "careerPrizeMoney": "$40000", "form": "11122",
             "scratched": False,
             "stats": {"overall": {"starts": 8, "wins": 3, "places": 6,
                                   "winPercent": 37.5, "placePercent": 75.0},
                       "track": {"starts": 3, "places": 2},
                       "distance": {"starts": 4, "places": 3},
                       "conditions": {"soft": {"starts": 2, "places": 1}}}},
            # a third runner but with almost no data (tests graceful degradation)
            {"number": 2, "name": "Ghost", "jockey": "P. Q", "trainer": "R. S",
             "barrier": 12, "scratched": False,
             "stats": {"overall": {"winPercent": 0.0, "placePercent": 0.0}}},
        ],
    }


def race_form_abandoned(date: str = "2026-08-11", track: str = "dubbo", race: int = 2) -> dict:
    return {"date": date, "track": track, "raceNumber": race, "abandoned": True,
            "runners": []}