package espn import ( "testing" "github.com/humdrum-tiv/sportsball/internal/model" ) func TestMapState(t *testing.T) { cases := map[string]model.State{ "pre": model.StatePre, "in": model.StateLive, "post": model.StateFinal, "unknown": model.StatePre, } for in, want := range cases { if got := mapState(in); got != want { t.Errorf("mapState(%q) = %v, want %v", in, got, want) } } } func TestMapEventScoresAndHomeAway(t *testing.T) { ev := event{ ID: "401", Date: "2026-06-16T22:40Z", Competitions: []competition{{ Status: status{Type: statusType{State: "in", Detail: "Top 5th"}, Period: 5}, Competitors: []competitor{ {HomeAway: "home", Score: "3", Team: teamJSON{Abbreviation: "PHI"}, Records: []record{{Type: "total", Summary: "40-30"}}}, {HomeAway: "away", Score: "5", Winner: true, Team: teamJSON{Abbreviation: "MIA"}}, }, }}, } g, ok := mapEvent(model.MLB, ev) if !ok { t.Fatal("mapEvent returned ok=false") } if g.State != model.StateLive { t.Errorf("state = %v, want Live", g.State) } if g.Home.Abbr != "PHI" || g.Home.Score != 3 || g.Home.Record != "40-30" { t.Errorf("home mapped wrong: %+v", g.Home) } if g.Away.Abbr != "MIA" || g.Away.Score != 5 || !g.Away.Winner { t.Errorf("away mapped wrong: %+v", g.Away) } } func TestSortGamesLiveFirst(t *testing.T) { gs := []model.Game{ {State: model.StateFinal}, {State: model.StatePre}, {State: model.StateLive}, } sortGames(gs) if gs[0].State != model.StateLive || gs[1].State != model.StatePre || gs[2].State != model.StateFinal { t.Errorf("sort order wrong: %v %v %v", gs[0].State, gs[1].State, gs[2].State) } } func TestMapSummarySoccerEvents(t *testing.T) { s := summary{ KeyEvents: []keyEvent{ { Type: eventType{Text: "Goal", Type: "goal"}, ShortText: "Jaidon Anthony Goal", Clock: eventClock{DisplayValue: "8'"}, Period: eventPeriod{Number: 1}, ScoringPlay: true, Team: eventTeam{DisplayName: "Burnley"}, Participants: []participant{ {Athlete: athleteRef{DisplayName: "Jaidon Anthony"}}, }, }, { Type: eventType{Text: "Yellow Card", Type: "yellow-card"}, Clock: eventClock{DisplayValue: "23'"}, Team: eventTeam{DisplayName: "Aston Villa"}, }, }, } d := mapSummary(s) if len(d.Events) != 2 { t.Fatalf("events = %d, want 2", len(d.Events)) } g := d.Events[0] if !g.Scoring || g.Clock != "8'" || g.Team != "Burnley" { t.Errorf("goal mapped wrong: %+v", g) } if len(g.Athletes) != 1 || g.Athletes[0] != "Jaidon Anthony" { t.Errorf("scorer mapped wrong: %+v", g.Athletes) } if d.Events[1].Type != "Yellow Card" { t.Errorf("card type = %q", d.Events[1].Type) } } func TestMapSummaryBoxScore(t *testing.T) { s := summary{ Boxscore: boxscore{ Players: []playerBox{{ Team: teamJSON{Abbreviation: "PHI", DisplayName: "Philadelphia Phillies"}, Statistics: []statGroup{{ Type: "batting", Labels: []string{"AB", "H", "RBI"}, Athletes: []athleteRow{ {Athlete: athleteRef{ShortName: "B. Marsh"}, Stats: []string{"4", "2", "1"}}, }, }}, }}, }, } d := mapSummary(s) if len(d.BoxScore) != 1 { t.Fatalf("teams = %d, want 1", len(d.BoxScore)) } tb := d.BoxScore[0] if tb.Abbr != "PHI" || len(tb.Groups) != 1 { t.Fatalf("team mapped wrong: %+v", tb) } grp := tb.Groups[0] if grp.Name != "batting" || len(grp.Rows) != 1 || grp.Rows[0].Athlete != "B. Marsh" { t.Errorf("group mapped wrong: %+v", grp) } if len(grp.Rows[0].Stats) != 3 || grp.Rows[0].Stats[1] != "2" { t.Errorf("stats mapped wrong: %+v", grp.Rows[0].Stats) } } func TestMapEventSituation(t *testing.T) { ev := event{ ID: "501", Date: "2026-06-16T22:40Z", Competitions: []competition{{ Status: status{Type: statusType{State: "in", Detail: "Top 7th"}, Period: 7}, Competitors: []competitor{ {HomeAway: "home", Score: "8", Team: teamJSON{Abbreviation: "PHI"}}, {HomeAway: "away", Score: "0", Team: teamJSON{Abbreviation: "MIA"}}, }, Situation: situationJSON{ Balls: 1, Strikes: 2, Outs: 1, OnSecond: true, Pitcher: playerSituation{Athlete: athleteRef{DisplayName: "Jesus Luzardo"}, Summary: "6.0 IP, 0 ER"}, Batter: playerSituation{Athlete: athleteRef{DisplayName: "Leo Jimenez"}, Summary: "0-2, K"}, }, }}, } g, ok := mapEvent(model.MLB, ev) if !ok || g.Situation == nil { t.Fatalf("situation not mapped: ok=%v sit=%v", ok, g.Situation) } s := g.Situation if s.Balls != 1 || s.Strikes != 2 || s.Outs != 1 || !s.OnSecond || s.OnFirst { t.Errorf("count/outs/bases wrong: %+v", s) } if s.Pitcher != "Jesus Luzardo" || s.Batter != "Leo Jimenez" || s.BatterLine != "0-2, K" { t.Errorf("pitcher/batter wrong: %+v", s) } } func TestMapEventNoSituationWhenFinal(t *testing.T) { ev := event{ ID: "502", Date: "2026-06-16T22:40Z", Competitions: []competition{{ Status: status{Type: statusType{State: "post"}}, Competitors: []competitor{{HomeAway: "home", Team: teamJSON{Abbreviation: "PHI"}}, {HomeAway: "away", Team: teamJSON{Abbreviation: "MIA"}}}, Situation: situationJSON{Pitcher: playerSituation{Athlete: athleteRef{DisplayName: "X"}}}, }}, } g, _ := mapEvent(model.MLB, ev) if g.Situation != nil { t.Errorf("final game should have no situation, got %+v", g.Situation) } } func TestMapSummaryScoringPlays(t *testing.T) { s := summary{Plays: []play{ {Text: "Bohm singled to right, Harper scored.", ScoringPlay: true, Period: playPeriod{Type: "Bottom", Number: 1}, Team: eventTeam{ID: "22"}, AlternativeType: altType{Text: "Single", Abbreviation: "1B"}}, {Text: "Strikeout swinging.", ScoringPlay: false, Period: playPeriod{Type: "Top", Number: 2}, Team: eventTeam{ID: "28"}}, {Text: "Schwarber homered to right (352 feet).", ScoringPlay: true, Period: playPeriod{Type: "Bottom", Number: 4}, Team: eventTeam{ID: "22"}, AlternativeType: altType{Text: "Home Run", Abbreviation: "HR"}}, }} d := mapSummary(s) if len(d.Events) != 2 { t.Fatalf("want 2 scoring events (non-scoring dropped), got %d", len(d.Events)) } e := d.Events[0] if e.Clock != "▼1" || e.TeamID != "22" || !e.Scoring || e.Type != "Single" { t.Errorf("first scoring play mapped wrong: %+v", e) } if d.Events[1].Clock != "▼4" || d.Events[1].Type != "Home Run" { t.Errorf("HR play mapped wrong: %+v", d.Events[1]) } }