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
|
package espn
import (
"testing"
"github.com/humdrum-tiv/sportsball/internal/model"
)
// mapStandings must flatten nested children (conference โ entries) into one
// group per table, select the per-sport columns, and rank by entry order.
func TestMapStandingsNestedAndColumns(t *testing.T) {
root := standingsNode{
Name: "National Basketball Association",
Children: []standingsNode{
{
Name: "Eastern Conference",
Standings: standingsBlock{Entries: []standingsEntry{
{
Team: teamJSON{ID: "1", Abbreviation: "BOS", ShortDisplayName: "Celtics"},
Stats: []standingStat{{Type: "wins", DisplayValue: "50"}, {Type: "losses", DisplayValue: "20"}, {Type: "winpercent", DisplayValue: ".714"}, {Type: "gamesbehind", DisplayValue: "-"}},
},
{
Team: teamJSON{ID: "2", Abbreviation: "NYK", ShortDisplayName: "Knicks"},
Stats: []standingStat{{Type: "wins", DisplayValue: "45"}, {Type: "losses", DisplayValue: "25"}},
},
}},
},
},
}
s := mapStandings(model.NBA, "basketball", root)
if len(s.Groups) != 1 {
t.Fatalf("want 1 group, got %d", len(s.Groups))
}
g := s.Groups[0]
if g.Name != "Eastern Conference" {
t.Errorf("group name = %q", g.Name)
}
wantCols := []string{"W", "L", "PCT", "GB"}
if len(g.Columns) != len(wantCols) {
t.Fatalf("columns = %v", g.Columns)
}
for i, c := range wantCols {
if g.Columns[i] != c {
t.Errorf("col %d = %q, want %q", i, g.Columns[i], c)
}
}
if g.Rows[0].Rank != 1 || g.Rows[0].Team.Abbr != "BOS" {
t.Errorf("row0 = %+v", g.Rows[0])
}
if got := g.Rows[0].Values; got[0] != "50" || got[1] != "20" || got[2] != ".714" || got[3] != "-" {
t.Errorf("row0 values = %v", got)
}
// Missing stats map to empty strings, not a panic.
if got := g.Rows[1].Values; got[2] != "" || got[3] != "" {
t.Errorf("row1 missing stats should be blank: %v", got)
}
}
// ESPN returns entries unsorted; mapStandings must order each group by the
// sport's rank stat (basketball = playoffseed) before assigning ranks.
func TestMapStandingsSortsByRankStat(t *testing.T) {
root := standingsNode{Standings: standingsBlock{Entries: []standingsEntry{
{Team: teamJSON{Abbreviation: "ATL"}, Stats: []standingStat{{Type: "playoffseed", DisplayValue: "6"}, {Type: "wins", DisplayValue: "46"}}},
{Team: teamJSON{Abbreviation: "DET"}, Stats: []standingStat{{Type: "playoffseed", DisplayValue: "1"}, {Type: "wins", DisplayValue: "60"}}},
{Team: teamJSON{Abbreviation: "BOS"}, Stats: []standingStat{{Type: "playoffseed", DisplayValue: "2"}, {Type: "wins", DisplayValue: "56"}}},
}}}
g := mapStandings(model.NBA, "basketball", root).Groups[0]
want := []string{"DET", "BOS", "ATL"}
for i, abbr := range want {
if g.Rows[i].Team.Abbr != abbr || g.Rows[i].Rank != i+1 {
t.Errorf("row %d = %s rank %d, want %s rank %d", i, g.Rows[i].Team.Abbr, g.Rows[i].Rank, abbr, i+1)
}
}
}
func TestStandingsRowAt(t *testing.T) {
s := model.Standings{Groups: []model.StandingsGroup{
{Rows: []model.StandingsRow{{Team: model.Team{Abbr: "A"}}, {Team: model.Team{Abbr: "B"}}}},
{Rows: []model.StandingsRow{{Team: model.Team{Abbr: "C"}}}},
}}
if s.RowCount() != 3 {
t.Fatalf("RowCount = %d", s.RowCount())
}
if r, ok := s.RowAt(2); !ok || r.Team.Abbr != "C" {
t.Errorf("RowAt(2) = %+v ok=%v, want C", r, ok)
}
if _, ok := s.RowAt(3); ok {
t.Error("RowAt(3) should be out of range")
}
}
|