cricinfo-cli-go 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +63 -0
- package/CONTRIBUTORS.md +75 -0
- package/LICENSE +21 -0
- package/Makefile +131 -0
- package/README.md +130 -0
- package/bin/cricinfo.js +44 -0
- package/cmd/cricinfo/main.go +15 -0
- package/go.mod +10 -0
- package/go.sum +10 -0
- package/internal/app/app.go +11 -0
- package/internal/app/app_test.go +122 -0
- package/internal/buildinfo/buildinfo.go +16 -0
- package/internal/cli/analysis.go +262 -0
- package/internal/cli/analysis_test.go +175 -0
- package/internal/cli/competitions.go +154 -0
- package/internal/cli/competitions_test.go +165 -0
- package/internal/cli/leagues.go +297 -0
- package/internal/cli/leagues_test.go +194 -0
- package/internal/cli/matches.go +403 -0
- package/internal/cli/matches_test.go +413 -0
- package/internal/cli/players.go +263 -0
- package/internal/cli/players_test.go +384 -0
- package/internal/cli/root.go +141 -0
- package/internal/cli/search.go +119 -0
- package/internal/cli/teams.go +214 -0
- package/internal/cli/teams_test.go +192 -0
- package/internal/cricinfo/analysis.go +1401 -0
- package/internal/cricinfo/analysis_phase15_test.go +267 -0
- package/internal/cricinfo/client.go +471 -0
- package/internal/cricinfo/client_test.go +280 -0
- package/internal/cricinfo/cmd/fixture-refresh/main.go +145 -0
- package/internal/cricinfo/competitions.go +405 -0
- package/internal/cricinfo/competitions_phase13_test.go +234 -0
- package/internal/cricinfo/coverage_ledger.go +122 -0
- package/internal/cricinfo/coverage_ledger_test.go +253 -0
- package/internal/cricinfo/decode.go +115 -0
- package/internal/cricinfo/decode_test.go +100 -0
- package/internal/cricinfo/entity_index.go +618 -0
- package/internal/cricinfo/entity_index_test.go +175 -0
- package/internal/cricinfo/fixture_matrix.go +243 -0
- package/internal/cricinfo/fixture_matrix_test.go +49 -0
- package/internal/cricinfo/fixtures_test.go +264 -0
- package/internal/cricinfo/historical_hydration.go +1641 -0
- package/internal/cricinfo/historical_phase14_test.go +542 -0
- package/internal/cricinfo/leagues.go +1210 -0
- package/internal/cricinfo/leagues_phase12_test.go +324 -0
- package/internal/cricinfo/live_leagues_test.go +169 -0
- package/internal/cricinfo/live_matches_test.go +203 -0
- package/internal/cricinfo/live_matrix_test.go +118 -0
- package/internal/cricinfo/live_players_test.go +122 -0
- package/internal/cricinfo/live_search_test.go +86 -0
- package/internal/cricinfo/live_smoke_test.go +213 -0
- package/internal/cricinfo/live_teams_test.go +104 -0
- package/internal/cricinfo/matches.go +1508 -0
- package/internal/cricinfo/matches_phase7_test.go +207 -0
- package/internal/cricinfo/matches_phase9_test.go +253 -0
- package/internal/cricinfo/normalize_entities.go +1727 -0
- package/internal/cricinfo/normalize_leagues.go +346 -0
- package/internal/cricinfo/players.go +1332 -0
- package/internal/cricinfo/players_phase10_test.go +174 -0
- package/internal/cricinfo/players_phase11_test.go +373 -0
- package/internal/cricinfo/render_contract.go +1088 -0
- package/internal/cricinfo/render_phase4_test.go +633 -0
- package/internal/cricinfo/renderer.go +1689 -0
- package/internal/cricinfo/resolver.go +813 -0
- package/internal/cricinfo/resolver_test.go +244 -0
- package/internal/cricinfo/teams.go +603 -0
- package/internal/cricinfo/teams_phase8_test.go +231 -0
- package/internal/cricinfo/testdata/fixtures/README.md +43 -0
- package/internal/cricinfo/testdata/fixtures/aux-competition-metadata/broadcasts.json +11 -0
- package/internal/cricinfo/testdata/fixtures/aux-competition-metadata/officials.json +150 -0
- package/internal/cricinfo/testdata/fixtures/details-plays/detail-110.json +157 -0
- package/internal/cricinfo/testdata/fixtures/details-plays/detail-52545007.json +145 -0
- package/internal/cricinfo/testdata/fixtures/details-plays/detail-52559021.json +143 -0
- package/internal/cricinfo/testdata/fixtures/details-plays/plays.json +15 -0
- package/internal/cricinfo/testdata/fixtures/endpoint-matrix.tsv +19 -0
- package/internal/cricinfo/testdata/fixtures/innings-fow-partnerships/fow-1.json +12 -0
- package/internal/cricinfo/testdata/fixtures/innings-fow-partnerships/fow.json +42 -0
- package/internal/cricinfo/testdata/fixtures/innings-fow-partnerships/innings-1-2.json +38 -0
- package/internal/cricinfo/testdata/fixtures/innings-fow-partnerships/partnership-1.json +31 -0
- package/internal/cricinfo/testdata/fixtures/innings-fow-partnerships/partnerships.json +42 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/calendar-offdays.json +20 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/calendar-ondays.json +21 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/calendar.json +14 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/season-2025.json +13 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/season-group-1.json +13 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/season-groups.json +11 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/season-type-1.json +13 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/season-types.json +11 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/seasons.json +30 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/standings-item-1.json +72 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/standings-root.json +3 -0
- package/internal/cricinfo/testdata/fixtures/leagues-seasons-standings/standings.json +15 -0
- package/internal/cricinfo/testdata/fixtures/matches-competitions/competition.json +460 -0
- package/internal/cricinfo/testdata/fixtures/matches-competitions/event-1529474.json +86 -0
- package/internal/cricinfo/testdata/fixtures/matches-competitions/matchcards-1527966.json +368 -0
- package/internal/cricinfo/testdata/fixtures/matches-competitions/situation-1529474.json +10 -0
- package/internal/cricinfo/testdata/fixtures/players/athlete-1361257-statistics.json +126 -0
- package/internal/cricinfo/testdata/fixtures/players/athlete-1361257.json +113 -0
- package/internal/cricinfo/testdata/fixtures/players/roster-1361257-linescores-1-1-statistics-0.json +208 -0
- package/internal/cricinfo/testdata/fixtures/players/roster-1361257-linescores-1-2-statistics-0.json +252 -0
- package/internal/cricinfo/testdata/fixtures/players/roster-1361257-linescores.json +74 -0
- package/internal/cricinfo/testdata/fixtures/players/roster-1361257-statistics-0.json +1008 -0
- package/internal/cricinfo/testdata/fixtures/root-discovery/events.json +72 -0
- package/internal/cricinfo/testdata/fixtures/root-discovery/root.json +28 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/competitor-789643.json +40 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/leaders-789643.json +353 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/records-789643.json +91 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/roster-1147772-object.json +231 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/roster-1147772.json +235 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/roster-789643.json +322 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/scores-789643.json +19 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/statistics-789643.json +629 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/team-789643-athletes.json +7 -0
- package/internal/cricinfo/testdata/fixtures/team-competitor/team-789643.json +67 -0
- package/internal/cricinfo/testdata/golden/match-empty.golden +1 -0
- package/internal/cricinfo/testdata/golden/match-list.golden +2 -0
- package/internal/cricinfo/testdata/golden/match-partial.golden +3 -0
- package/internal/cricinfo/types.go +54 -0
- package/package.json +51 -0
- package/scripts/postinstall.js +153 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
package cricinfo
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"path/filepath"
|
|
5
|
+
"testing"
|
|
6
|
+
"time"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func TestEntityIndexSearchExactAndFuzzy(t *testing.T) {
|
|
10
|
+
t.Parallel()
|
|
11
|
+
|
|
12
|
+
idx, err := OpenEntityIndex(filepath.Join(t.TempDir(), "index.json"))
|
|
13
|
+
if err != nil {
|
|
14
|
+
t.Fatalf("OpenEntityIndex error: %v", err)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
now := time.Now().UTC()
|
|
18
|
+
if err := idx.Upsert(IndexedEntity{
|
|
19
|
+
Kind: EntityPlayer,
|
|
20
|
+
ID: "1361257",
|
|
21
|
+
Ref: "http://core.espnuk.org/v2/sports/cricket/athletes/1361257",
|
|
22
|
+
Name: "Fazal Haq Shaheen",
|
|
23
|
+
ShortName: "Fazal",
|
|
24
|
+
Aliases: []string{"Fazal Haq", "Shaheen"},
|
|
25
|
+
UpdatedAt: now,
|
|
26
|
+
}); err != nil {
|
|
27
|
+
t.Fatalf("Upsert player 1 error: %v", err)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if err := idx.Upsert(IndexedEntity{
|
|
31
|
+
Kind: EntityPlayer,
|
|
32
|
+
ID: "999",
|
|
33
|
+
Name: "John Doe",
|
|
34
|
+
Aliases: []string{"Johnny"},
|
|
35
|
+
UpdatedAt: now.Add(-time.Minute),
|
|
36
|
+
}); err != nil {
|
|
37
|
+
t.Fatalf("Upsert player 2 error: %v", err)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exact := idx.Search(EntityPlayer, "1361257", 5, SearchContext{})
|
|
41
|
+
if len(exact) == 0 || exact[0].ID != "1361257" {
|
|
42
|
+
t.Fatalf("expected exact id match for 1361257, got %+v", exact)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fuzzy := idx.Search(EntityPlayer, "faz sha", 5, SearchContext{})
|
|
46
|
+
if len(fuzzy) == 0 || fuzzy[0].ID != "1361257" {
|
|
47
|
+
t.Fatalf("expected fuzzy alias match for 'faz sha', got %+v", fuzzy)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
func TestEntityIndexSearchContextBoost(t *testing.T) {
|
|
52
|
+
t.Parallel()
|
|
53
|
+
|
|
54
|
+
idx, err := OpenEntityIndex(filepath.Join(t.TempDir(), "index.json"))
|
|
55
|
+
if err != nil {
|
|
56
|
+
t.Fatalf("OpenEntityIndex error: %v", err)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if err := idx.Upsert(IndexedEntity{
|
|
60
|
+
Kind: EntityMatch,
|
|
61
|
+
ID: "1529474",
|
|
62
|
+
Name: "3rd Match",
|
|
63
|
+
LeagueID: "19138",
|
|
64
|
+
MatchID: "1529474",
|
|
65
|
+
UpdatedAt: time.Now().UTC(),
|
|
66
|
+
}); err != nil {
|
|
67
|
+
t.Fatalf("Upsert preferred match error: %v", err)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if err := idx.Upsert(IndexedEntity{
|
|
71
|
+
Kind: EntityMatch,
|
|
72
|
+
ID: "1529999",
|
|
73
|
+
Name: "3rd Match",
|
|
74
|
+
LeagueID: "11132",
|
|
75
|
+
MatchID: "1529999",
|
|
76
|
+
UpdatedAt: time.Now().UTC(),
|
|
77
|
+
}); err != nil {
|
|
78
|
+
t.Fatalf("Upsert non-preferred match error: %v", err)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
results := idx.Search(EntityMatch, "3rd match", 5, SearchContext{PreferredLeagueID: "19138"})
|
|
82
|
+
if len(results) == 0 {
|
|
83
|
+
t.Fatalf("expected search results")
|
|
84
|
+
}
|
|
85
|
+
if results[0].ID != "1529474" {
|
|
86
|
+
t.Fatalf("expected context-preferred match first, got %+v", results)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func TestEntityIndexSearchPrefersExactMatchContext(t *testing.T) {
|
|
91
|
+
t.Parallel()
|
|
92
|
+
|
|
93
|
+
idx, err := OpenEntityIndex(filepath.Join(t.TempDir(), "index.json"))
|
|
94
|
+
if err != nil {
|
|
95
|
+
t.Fatalf("OpenEntityIndex error: %v", err)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
now := time.Now().UTC()
|
|
99
|
+
entities := []IndexedEntity{
|
|
100
|
+
{
|
|
101
|
+
Kind: EntityPlayer,
|
|
102
|
+
ID: "253802",
|
|
103
|
+
Name: "Virat Kohli",
|
|
104
|
+
LeagueID: "11132",
|
|
105
|
+
MatchID: "1527689",
|
|
106
|
+
UpdatedAt: now,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
Kind: EntityPlayer,
|
|
110
|
+
ID: "999999",
|
|
111
|
+
Name: "Virat Kohli",
|
|
112
|
+
LeagueID: "19138",
|
|
113
|
+
MatchID: "1529474",
|
|
114
|
+
UpdatedAt: now.Add(time.Minute),
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
if err := idx.UpsertMany(entities); err != nil {
|
|
118
|
+
t.Fatalf("UpsertMany error: %v", err)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
results := idx.Search(EntityPlayer, "virat kohli", 5, SearchContext{
|
|
122
|
+
PreferredLeagueID: "11132",
|
|
123
|
+
PreferredMatchID: "1527689",
|
|
124
|
+
})
|
|
125
|
+
if len(results) == 0 {
|
|
126
|
+
t.Fatalf("expected contextual player search results")
|
|
127
|
+
}
|
|
128
|
+
if results[0].ID != "253802" {
|
|
129
|
+
t.Fatalf("expected preferred match-context player first, got %+v", results)
|
|
130
|
+
}
|
|
131
|
+
for _, result := range results {
|
|
132
|
+
if result.MatchID != "1527689" {
|
|
133
|
+
t.Fatalf("expected results to be narrowed to preferred match context, got %+v", results)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
func TestEntityIndexSearchDoesNotMatchInitialForFullNameQuery(t *testing.T) {
|
|
139
|
+
t.Parallel()
|
|
140
|
+
|
|
141
|
+
idx, err := OpenEntityIndex(filepath.Join(t.TempDir(), "index.json"))
|
|
142
|
+
if err != nil {
|
|
143
|
+
t.Fatalf("OpenEntityIndex error: %v", err)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
now := time.Now().UTC()
|
|
147
|
+
if err := idx.UpsertMany([]IndexedEntity{
|
|
148
|
+
{
|
|
149
|
+
Kind: EntityPlayer,
|
|
150
|
+
ID: "253802",
|
|
151
|
+
Name: "Virat Kohli",
|
|
152
|
+
ShortName: "Kohli",
|
|
153
|
+
Aliases: []string{"Virat Kohli", "V Kohli"},
|
|
154
|
+
UpdatedAt: now,
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
Kind: EntityPlayer,
|
|
158
|
+
ID: "1408688",
|
|
159
|
+
Name: "Vaibhav Sooryavanshi",
|
|
160
|
+
ShortName: "Sooryavanshi",
|
|
161
|
+
Aliases: []string{"Vaibhav Sooryavanshi", "V Sooryavanshi"},
|
|
162
|
+
UpdatedAt: now.Add(time.Minute),
|
|
163
|
+
},
|
|
164
|
+
}); err != nil {
|
|
165
|
+
t.Fatalf("UpsertMany error: %v", err)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
results := idx.Search(EntityPlayer, "Virat Kohli", 5, SearchContext{})
|
|
169
|
+
if len(results) == 0 {
|
|
170
|
+
t.Fatalf("expected player search results")
|
|
171
|
+
}
|
|
172
|
+
if results[0].ID != "253802" {
|
|
173
|
+
t.Fatalf("expected exact full-name match first, got %+v", results)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
package cricinfo
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"sort"
|
|
6
|
+
"strings"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// FixtureFamily groups fixtures and live probes by API resource family.
|
|
10
|
+
type FixtureFamily string
|
|
11
|
+
|
|
12
|
+
const (
|
|
13
|
+
FixtureFamilyRootDiscovery FixtureFamily = "root-discovery"
|
|
14
|
+
FixtureFamilyMatchesCompetition FixtureFamily = "matches-competitions"
|
|
15
|
+
FixtureFamilyDetailsPlays FixtureFamily = "details-plays"
|
|
16
|
+
FixtureFamilyTeamCompetitor FixtureFamily = "team-competitor"
|
|
17
|
+
FixtureFamilyInningsDepth FixtureFamily = "innings-fow-partnerships"
|
|
18
|
+
FixtureFamilyPlayers FixtureFamily = "players"
|
|
19
|
+
FixtureFamilyLeagueSeason FixtureFamily = "leagues-seasons-standings"
|
|
20
|
+
FixtureFamilyAuxCompetitionMeta FixtureFamily = "aux-competition-metadata"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
// FixtureSpec defines a curated fixture/live endpoint pairing.
|
|
24
|
+
type FixtureSpec struct {
|
|
25
|
+
Family FixtureFamily
|
|
26
|
+
Name string
|
|
27
|
+
Ref string
|
|
28
|
+
FixturePath string
|
|
29
|
+
LiveProbe bool
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var fixtureSpecs = []FixtureSpec{
|
|
33
|
+
{
|
|
34
|
+
Family: FixtureFamilyRootDiscovery,
|
|
35
|
+
Name: "root",
|
|
36
|
+
Ref: "/v2/sports/cricket",
|
|
37
|
+
FixturePath: "root-discovery/root.json",
|
|
38
|
+
LiveProbe: true,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
Family: FixtureFamilyRootDiscovery,
|
|
42
|
+
Name: "events-page",
|
|
43
|
+
Ref: "/events",
|
|
44
|
+
FixturePath: "root-discovery/events.json",
|
|
45
|
+
LiveProbe: false,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
Family: FixtureFamilyMatchesCompetition,
|
|
49
|
+
Name: "competition",
|
|
50
|
+
Ref: "/leagues/19138/events/1529474/competitions/1529474",
|
|
51
|
+
FixturePath: "matches-competitions/competition.json",
|
|
52
|
+
LiveProbe: true,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
Family: FixtureFamilyMatchesCompetition,
|
|
56
|
+
Name: "matchcards",
|
|
57
|
+
Ref: "/leagues/11132/events/1527966/competitions/1527966/matchcards",
|
|
58
|
+
FixturePath: "matches-competitions/matchcards-1527966.json",
|
|
59
|
+
LiveProbe: false,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
Family: FixtureFamilyMatchesCompetition,
|
|
63
|
+
Name: "situation",
|
|
64
|
+
Ref: "/leagues/19138/events/1529474/competitions/1529474/situation",
|
|
65
|
+
FixturePath: "matches-competitions/situation-1529474.json",
|
|
66
|
+
LiveProbe: false,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
Family: FixtureFamilyDetailsPlays,
|
|
70
|
+
Name: "plays-page",
|
|
71
|
+
Ref: "/leagues/19138/events/1529474/competitions/1529474/plays?limit=1",
|
|
72
|
+
FixturePath: "details-plays/plays.json",
|
|
73
|
+
LiveProbe: true,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
Family: FixtureFamilyDetailsPlays,
|
|
77
|
+
Name: "detail-item",
|
|
78
|
+
Ref: "/leagues/19138/events/1529474/competitions/1529474/details/110",
|
|
79
|
+
FixturePath: "details-plays/detail-110.json",
|
|
80
|
+
LiveProbe: false,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
Family: FixtureFamilyTeamCompetitor,
|
|
84
|
+
Name: "competitor",
|
|
85
|
+
Ref: "/leagues/19138/events/1529474/competitions/1529474/competitors/789643",
|
|
86
|
+
FixturePath: "team-competitor/competitor-789643.json",
|
|
87
|
+
LiveProbe: true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
Family: FixtureFamilyTeamCompetitor,
|
|
91
|
+
Name: "competitor-roster",
|
|
92
|
+
Ref: "/leagues/11132/events/1475396/competitions/1475396/competitors/1147772/roster",
|
|
93
|
+
FixturePath: "team-competitor/roster-1147772.json",
|
|
94
|
+
LiveProbe: false,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
Family: FixtureFamilyInningsDepth,
|
|
98
|
+
Name: "innings-period",
|
|
99
|
+
Ref: "/leagues/1098952/events/1475396/competitions/1475396/competitors/1147772/linescores/1/2",
|
|
100
|
+
FixturePath: "innings-fow-partnerships/innings-1-2.json",
|
|
101
|
+
LiveProbe: true,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
Family: FixtureFamilyInningsDepth,
|
|
105
|
+
Name: "fow",
|
|
106
|
+
Ref: "/leagues/1098952/events/1475396/competitions/1475396/competitors/1147772/linescores/1/2/fow",
|
|
107
|
+
FixturePath: "innings-fow-partnerships/fow.json",
|
|
108
|
+
LiveProbe: false,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
Family: FixtureFamilyInningsDepth,
|
|
112
|
+
Name: "partnerships",
|
|
113
|
+
Ref: "/leagues/1098952/events/1475396/competitions/1475396/competitors/1147772/linescores/1/2/partnerships",
|
|
114
|
+
FixturePath: "innings-fow-partnerships/partnerships.json",
|
|
115
|
+
LiveProbe: false,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
Family: FixtureFamilyPlayers,
|
|
119
|
+
Name: "athlete-profile",
|
|
120
|
+
Ref: "/athletes/1361257",
|
|
121
|
+
FixturePath: "players/athlete-1361257.json",
|
|
122
|
+
LiveProbe: true,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
Family: FixtureFamilyPlayers,
|
|
126
|
+
Name: "athlete-statistics",
|
|
127
|
+
Ref: "/athletes/1361257/statistics",
|
|
128
|
+
FixturePath: "players/athlete-1361257-statistics.json",
|
|
129
|
+
LiveProbe: false,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
Family: FixtureFamilyLeagueSeason,
|
|
133
|
+
Name: "standings",
|
|
134
|
+
Ref: "/leagues/19138/standings",
|
|
135
|
+
FixturePath: "leagues-seasons-standings/standings.json",
|
|
136
|
+
LiveProbe: true,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
Family: FixtureFamilyLeagueSeason,
|
|
140
|
+
Name: "seasons",
|
|
141
|
+
Ref: "/leagues/19138/seasons",
|
|
142
|
+
FixturePath: "leagues-seasons-standings/seasons.json",
|
|
143
|
+
LiveProbe: false,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
Family: FixtureFamilyAuxCompetitionMeta,
|
|
147
|
+
Name: "officials",
|
|
148
|
+
Ref: "/leagues/11132/events/1527944/competitions/1527944/officials",
|
|
149
|
+
FixturePath: "aux-competition-metadata/officials.json",
|
|
150
|
+
LiveProbe: true,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
Family: FixtureFamilyAuxCompetitionMeta,
|
|
154
|
+
Name: "broadcasts",
|
|
155
|
+
Ref: "/leagues/11132/events/1527944/competitions/1527944/broadcasts",
|
|
156
|
+
FixturePath: "aux-competition-metadata/broadcasts.json",
|
|
157
|
+
LiveProbe: false,
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// FixtureMatrix returns a copy of the curated fixture endpoint matrix.
|
|
162
|
+
func FixtureMatrix() []FixtureSpec {
|
|
163
|
+
out := make([]FixtureSpec, len(fixtureSpecs))
|
|
164
|
+
copy(out, fixtureSpecs)
|
|
165
|
+
return out
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// FixtureFamilies returns sorted family names represented in the matrix.
|
|
169
|
+
func FixtureFamilies() []FixtureFamily {
|
|
170
|
+
seen := map[FixtureFamily]struct{}{}
|
|
171
|
+
for _, spec := range fixtureSpecs {
|
|
172
|
+
seen[spec.Family] = struct{}{}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
families := make([]FixtureFamily, 0, len(seen))
|
|
176
|
+
for family := range seen {
|
|
177
|
+
families = append(families, family)
|
|
178
|
+
}
|
|
179
|
+
sort.Slice(families, func(i, j int) bool { return families[i] < families[j] })
|
|
180
|
+
|
|
181
|
+
return families
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ParseFixtureFamilies parses a comma-separated family filter.
|
|
185
|
+
func ParseFixtureFamilies(raw string) (map[FixtureFamily]struct{}, error) {
|
|
186
|
+
raw = strings.TrimSpace(raw)
|
|
187
|
+
if raw == "" {
|
|
188
|
+
return nil, nil
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
allowed := map[FixtureFamily]struct{}{}
|
|
192
|
+
for _, family := range FixtureFamilies() {
|
|
193
|
+
allowed[family] = struct{}{}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
selected := map[FixtureFamily]struct{}{}
|
|
197
|
+
parts := strings.Split(raw, ",")
|
|
198
|
+
for _, part := range parts {
|
|
199
|
+
family := FixtureFamily(strings.TrimSpace(part))
|
|
200
|
+
if family == "" {
|
|
201
|
+
continue
|
|
202
|
+
}
|
|
203
|
+
if _, ok := allowed[family]; !ok {
|
|
204
|
+
return nil, fmt.Errorf("unknown fixture family %q", family)
|
|
205
|
+
}
|
|
206
|
+
selected[family] = struct{}{}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if len(selected) == 0 {
|
|
210
|
+
return nil, nil
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return selected, nil
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// FilterFixtureMatrixByFamily filters the matrix by selected families.
|
|
217
|
+
func FilterFixtureMatrixByFamily(matrix []FixtureSpec, selected map[FixtureFamily]struct{}) []FixtureSpec {
|
|
218
|
+
if len(selected) == 0 {
|
|
219
|
+
out := make([]FixtureSpec, len(matrix))
|
|
220
|
+
copy(out, matrix)
|
|
221
|
+
return out
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
out := make([]FixtureSpec, 0, len(matrix))
|
|
225
|
+
for _, spec := range matrix {
|
|
226
|
+
if _, ok := selected[spec.Family]; ok {
|
|
227
|
+
out = append(out, spec)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return out
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// LiveProbeMatrix returns one or more live probe entries from the matrix.
|
|
235
|
+
func LiveProbeMatrix(matrix []FixtureSpec) []FixtureSpec {
|
|
236
|
+
out := make([]FixtureSpec, 0, len(matrix))
|
|
237
|
+
for _, spec := range matrix {
|
|
238
|
+
if spec.LiveProbe {
|
|
239
|
+
out = append(out, spec)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return out
|
|
243
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
package cricinfo
|
|
2
|
+
|
|
3
|
+
import "testing"
|
|
4
|
+
|
|
5
|
+
func TestFixtureMatrixCoversAllMajorFamilies(t *testing.T) {
|
|
6
|
+
t.Parallel()
|
|
7
|
+
|
|
8
|
+
required := []FixtureFamily{
|
|
9
|
+
FixtureFamilyRootDiscovery,
|
|
10
|
+
FixtureFamilyMatchesCompetition,
|
|
11
|
+
FixtureFamilyDetailsPlays,
|
|
12
|
+
FixtureFamilyTeamCompetitor,
|
|
13
|
+
FixtureFamilyInningsDepth,
|
|
14
|
+
FixtureFamilyPlayers,
|
|
15
|
+
FixtureFamilyLeagueSeason,
|
|
16
|
+
FixtureFamilyAuxCompetitionMeta,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
matrix := FixtureMatrix()
|
|
20
|
+
found := map[FixtureFamily]int{}
|
|
21
|
+
for _, spec := range matrix {
|
|
22
|
+
found[spec.Family]++
|
|
23
|
+
if spec.Name == "" || spec.Ref == "" || spec.FixturePath == "" {
|
|
24
|
+
t.Fatalf("invalid fixture spec %+v", spec)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
for _, family := range required {
|
|
29
|
+
if found[family] == 0 {
|
|
30
|
+
t.Fatalf("missing fixture coverage for family %q", family)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func TestParseFixtureFamilies(t *testing.T) {
|
|
36
|
+
t.Parallel()
|
|
37
|
+
|
|
38
|
+
selected, err := ParseFixtureFamilies("players,details-plays")
|
|
39
|
+
if err != nil {
|
|
40
|
+
t.Fatalf("ParseFixtureFamilies error: %v", err)
|
|
41
|
+
}
|
|
42
|
+
if len(selected) != 2 {
|
|
43
|
+
t.Fatalf("expected 2 selected families, got %d", len(selected))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if _, err := ParseFixtureFamilies("players,unknown"); err == nil {
|
|
47
|
+
t.Fatalf("expected parse error for unknown family")
|
|
48
|
+
}
|
|
49
|
+
}
|