From dcd2277fb9f29b29536277ac3403e7010d0f5554 Mon Sep 17 00:00:00 2001 From: Graham Plata Date: Fri, 16 Oct 2020 20:15:50 -0400 Subject: [PATCH] Refactor and update tests (#11) --- api/api.go | 101 +++++++------------------------------- api/api_test.go | 113 +++--------------------------------------- api/model.go | 5 ++ cmd/next.go | 2 +- cmd/record.go | 4 +- cmd/schedule.go | 2 +- handlers/handlers.go | 114 +++++++++++++++++++++++++++++++++++++++++++ handlers/next.go | 28 ----------- handlers/record.go | 29 ----------- handlers/schedule.go | 32 ------------ 10 files changed, 145 insertions(+), 285 deletions(-) create mode 100644 handlers/handlers.go delete mode 100644 handlers/next.go delete mode 100644 handlers/record.go delete mode 100644 handlers/schedule.go diff --git a/api/api.go b/api/api.go index caa8da4..729ce48 100644 --- a/api/api.go +++ b/api/api.go @@ -9,102 +9,35 @@ import ( "encoding/json" "fmt" "io/ioutil" + "log" "net/http" - "strconv" - "strings" - "time" - "github.com/bndr/gotabulate" "github.com/grahamplata/sixers/config" - "github.com/logrusorgru/aurora" + "github.com/grahamplata/sixers/utils" ) -// BuildURL takes the query parameters and returns a string to be used to retrieve data from the api -func BuildURL(seasonYearStart string, seasonYearEnd string) string { - // TODO currently paging is hard coded address this later - url := fmt.Sprintf("%s/?seasons[]=%s,%s&postseason=False&team_ids[]=%v&per_page=100", config.APIURL, seasonYearStart, seasonYearEnd, config.TeamID) +// urlBuilder takes the query parameters and returns a string to be used to retrieve data from the api +func urlBuilder(r Request) string { + url := fmt.Sprintf("%s/?seasons[]=%s,%s&postseason=False&team_ids[]=%v&per_page=100", + config.APIURL, r.Year, utils.DecrementString(r.Year), config.TeamID) return url } -// NextResponse ... -func NextResponse(response *http.Response) string { +// Fetch ... +func Fetch(r Request) Response { var responseObject Response - responseData, _ := ioutil.ReadAll(response.Body) - json.Unmarshal(responseData, &responseObject) - - for _, v := range responseObject.Data { - if v.Status != "Final" { - gameTime := strings.TrimRight(v.Time, " ") - resp := fmt.Sprintf("10,9 8 %s! There is a game currently @ %s %+s\n", config.SixersLogo, v.Status, gameTime) - return resp - } + url := urlBuilder(r) + response, err := http.Get(url) + if err != nil { + log.Fatal(err) } - return "Sorry, there are not any available games." -} - -// RecordResponse ... -func RecordResponse(response *http.Response) string { - var gameCount, winRecord int - var responseObject Response - - responseData, _ := ioutil.ReadAll(response.Body) - json.Unmarshal(responseData, &responseObject) - for _, v := range responseObject.Data { - if v.VisitorTeamScore != 0 || v.HomeTeamScore != 0 { - if v.HomeTeam.ID == config.TeamID { - if v.HomeTeamScore > v.VisitorTeamScore { - winRecord++ - } - } else { - if v.HomeTeamScore < v.VisitorTeamScore { - winRecord++ - } - } - gameCount++ - } + body, err := ioutil.ReadAll(response.Body) + if err != nil { + log.Fatal(err) } - wins := fmt.Sprintf("%s %d", aurora.Green("Wins:"), winRecord) - losses := fmt.Sprintf("%s %d", aurora.Red("Losses:"), (gameCount - winRecord)) - pct := fmt.Sprintf("%s %.3f", aurora.Yellow("Win pct:"), (float64(winRecord) / float64(gameCount))) - return fmt.Sprintf("%s %s %s", wins, losses, pct) -} + json.Unmarshal(body, &responseObject) -// ScheduleResponse ... -func ScheduleResponse(response *http.Response) string { - var headers = []string{"Game", "Date", "Home", "Away", "Winner"} - var responseObject Response - var table [][]string - - responseData, _ := ioutil.ReadAll(response.Body) - json.Unmarshal(responseData, &responseObject) - - for i, v := range responseObject.Data { - var winner string - parsedTime, _ := time.Parse(time.RFC3339, v.Date) - formattedTime := parsedTime.Format(config.LayoutUS) - gameNum := strconv.Itoa(i + 1) - home := fmt.Sprintf("%s: %v", v.HomeTeam.Abbreviation, v.HomeTeamScore) - away := fmt.Sprintf("%s: %v", v.VisitorTeam.Abbreviation, v.VisitorTeamScore) - - if v.VisitorTeamScore != 0 || v.HomeTeamScore != 0 { - if v.HomeTeam.ID == config.TeamID { - if v.HomeTeamScore > v.VisitorTeamScore { - winner = v.HomeTeam.FullName - } - } else { - if v.HomeTeamScore < v.VisitorTeamScore { - winner = v.HomeTeam.FullName - } - } - winner = v.VisitorTeam.FullName - } - - game := []string{gameNum, formattedTime, home, away, winner} - table = append(table, game) - } - tabulate := gotabulate.Create(table) - tabulate.SetHeaders(headers) - return tabulate.Render("simple") + return responseObject } diff --git a/api/api_test.go b/api/api_test.go index add26d6..0927676 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -5,123 +5,22 @@ Copyright © 2019 Graham Plata */ import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "strings" "testing" - - "github.com/grahamplata/sixers/config" ) var urlTests = []struct { - n string // input - m string // input - expected string // expected result + n Request // input + expected string // expected result }{ - {"a", "b", "https://www.balldontlie.io/api/v1/games/?seasons[]=a,b&postseason=False&team_ids[]=23&per_page=100"}, - {"1", "2", "https://www.balldontlie.io/api/v1/games/?seasons[]=1,2&postseason=False&team_ids[]=23&per_page=100"}, - {"21", "2009", "https://www.balldontlie.io/api/v1/games/?seasons[]=21,2009&postseason=False&team_ids[]=23&per_page=100"}, - {"2019", "2020", "https://www.balldontlie.io/api/v1/games/?seasons[]=2019,2020&postseason=False&team_ids[]=23&per_page=100"}, + {Request{Year: "2009"}, "https://www.balldontlie.io/api/v1/games/?seasons[]=2009,2008&postseason=False&team_ids[]=23&per_page=100"}, + {Request{Year: "2020"}, "https://www.balldontlie.io/api/v1/games/?seasons[]=2020,2019&postseason=False&team_ids[]=23&per_page=100"}, } func TestBuildURL(t *testing.T) { for _, tt := range urlTests { - actual := BuildURL(tt.n, tt.m) + actual := urlBuilder(tt.n) if actual != tt.expected { - t.Errorf("BuildURL(%s,%s): expected %s, actual %s", tt.n, tt.m, tt.expected, actual) + t.Errorf("BuildURL(%s): expected %s, actual %s", tt.n, tt.expected, actual) } } } - -var dummy = Response{ - Data: []Game{ - { - ID: 1, - Date: "2018-10-16T00:00:00.000Z", - HomeTeamScore: 123, - VisitorTeamScore: 122, - Season: 2020, - Period: 1, - Status: "Final", - Time: " ", - PostSeason: false, - HomeTeam: Team{ - ID: 1, - Abbreviation: "BOS", - City: "Boston", - Conference: "East", - Division: "Atlantic", - FullName: "Boston Celtics", - Name: "Celtics", - }, - VisitorTeam: Team{ - ID: 23, - Abbreviation: "PHI", - City: "Philadelphia", - Conference: "East", - Division: "Atlantic", - FullName: "Philadelphia 76ers", - Name: "76ers", - }, - }, - }, -} - -func TestNextResponseNoGameTonight(t *testing.T) { - body, _ := json.Marshal(dummy) - q := &http.Response{ - Status: "200 OK", - StatusCode: 200, - Proto: "HTTP/1.1", - ProtoMajor: 1, - ProtoMinor: 1, - Body: ioutil.NopCloser(bytes.NewReader(body)), - ContentLength: int64(len(body)), - Header: make(http.Header, 0), - } - actual := NextResponse(q) - if actual != "Sorry, there are not any available games." { - t.Errorf("NextResponse(stub): expected false, actual %s", actual) - } -} - -func TestNextResponseGameTonight(t *testing.T) { - dummy.Data[0].Status = "8PM" - body, _ := json.Marshal(dummy) - q := &http.Response{ - Status: "200 OK", - StatusCode: 200, - Proto: "HTTP/1.1", - ProtoMajor: 1, - ProtoMinor: 1, - Body: ioutil.NopCloser(bytes.NewReader(body)), - ContentLength: int64(len(body)), - Header: make(http.Header, 0), - } - actual := NextResponse(q) - gameTime := strings.TrimRight(dummy.Data[0].Time, " ") - if actual != fmt.Sprintf("10,9 8 %s! There is a game currently @ %s %+s\n", config.SixersLogo, dummy.Data[0].Status, gameTime) { - t.Errorf("NextResponse(stub): expected false, actual %s", actual) - } -} - -func TestRecordResponse(t *testing.T) { - body, _ := json.Marshal(dummy) - q := &http.Response{ - Status: "200 OK", - StatusCode: 200, - Proto: "HTTP/1.1", - ProtoMajor: 1, - ProtoMinor: 1, - Body: ioutil.NopCloser(bytes.NewReader(body)), - ContentLength: int64(len(body)), - Header: make(http.Header, 0), - } - actual := RecordResponse(q) - if actual == "1" { - t.Errorf("NextResponse(stub): expected 1, actual %s", actual) - } -} diff --git a/api/model.go b/api/model.go index d362434..30c59be 100644 --- a/api/model.go +++ b/api/model.go @@ -4,6 +4,11 @@ Copyright © 2019 Graham Plata package api +// A Request Struct to map request parameters to. +type Request struct { + Year string +} + // A Response Struct to map response to. type Response struct { Data []Game `json:"data"` diff --git a/cmd/next.go b/cmd/next.go index ede6a0f..db71b30 100644 --- a/cmd/next.go +++ b/cmd/next.go @@ -11,7 +11,7 @@ var nextCmd = &cobra.Command{ Short: "Fetches the next available sixers game date and time.", Long: "Fetches the next available sixers game date and time.", Run: func(cmd *cobra.Command, args []string) { - handlers.Next(cmd, args) + handlers.Next() }, } diff --git a/cmd/record.go b/cmd/record.go index 5c29b7e..9d27952 100644 --- a/cmd/record.go +++ b/cmd/record.go @@ -5,18 +5,16 @@ import ( "github.com/spf13/cobra" ) -// recordCmd represents the record command var recordCmd = &cobra.Command{ Use: "record", Short: "Fetches the record for the current season.", Long: "Fetches the record for the current season.", Run: func(cmd *cobra.Command, args []string) { - handlers.Record(cmd, args) + handlers.Record(cmd) }, } func init() { rootCmd.AddCommand(recordCmd) - // Here you will define your flags and configuration settings. recordCmd.Flags().StringP("year", "y", "", "The year of the season you would like to query") } diff --git a/cmd/schedule.go b/cmd/schedule.go index d33ad5f..e9aa974 100644 --- a/cmd/schedule.go +++ b/cmd/schedule.go @@ -11,7 +11,7 @@ var scheduleCmd = &cobra.Command{ Short: "An at a glance view of the Sixers NBA season.", Long: `An at a glance view of the Sixers NBA season.`, Run: func(cmd *cobra.Command, args []string) { - handlers.Schedule(cmd, args) + handlers.Schedule(cmd) }, } diff --git a/handlers/handlers.go b/handlers/handlers.go new file mode 100644 index 0000000..784dab6 --- /dev/null +++ b/handlers/handlers.go @@ -0,0 +1,114 @@ +package handlers + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/bndr/gotabulate" + "github.com/grahamplata/sixers/api" + "github.com/grahamplata/sixers/config" + "github.com/logrusorgru/aurora" + "github.com/spf13/cobra" +) + +// Next handles when the next sixers game is available +func Next() { + requestParams := api.Request{Year: time.Now().Format(config.YearFormat)} + results := api.Fetch(requestParams) + for _, v := range results.Data { + if v.Status != "Final" { + gameTime := strings.TrimRight(v.Time, " ") + nextResponse := fmt.Sprintf("10,9 8 %s! There is a game currently @ %s %+s\n", config.SixersLogo, v.Status, gameTime) + fmt.Println(nextResponse) + } + } +} + +// Record handles the record statistics +func Record(cmd *cobra.Command) { + var gameCount, winRecord int + var requestParams api.Request + + yearFlag := cmd.Flag("year") + + if yearFlag.Value.String() == "" { + requestParams.Year = time.Now().Format(config.YearFormat) + } else { + // TODO add format check + requestParams.Year = yearFlag.Value.String() + } + + results := api.Fetch(requestParams) + + for _, v := range results.Data { + if v.VisitorTeamScore != 0 || v.HomeTeamScore != 0 { + if v.HomeTeam.ID == config.TeamID { + if v.HomeTeamScore > v.VisitorTeamScore { + winRecord++ + } + } else { + if v.HomeTeamScore < v.VisitorTeamScore { + winRecord++ + } + } + gameCount++ + } + } + + wins := fmt.Sprintf("%s %d", aurora.Green("Wins:"), winRecord) + losses := fmt.Sprintf("%s %d", aurora.Red("Losses:"), (gameCount - winRecord)) + pct := fmt.Sprintf("%s %.3f", aurora.Yellow("Win pct:"), (float64(winRecord) / float64(gameCount))) + final := fmt.Sprintf("%s %s %s", wins, losses, pct) + + fmt.Println(final) +} + +// Schedule handles when the next sixers game is available +func Schedule(cmd *cobra.Command) { + var headers = []string{"Game", "Date", "Home", "Away", "Winner"} + var table [][]string + var requestParams api.Request + + yearFlag := cmd.Flag("year") + + if yearFlag.Value.String() == "" { + requestParams.Year = time.Now().Format(config.YearFormat) + } else { + // TODO add format check + requestParams.Year = yearFlag.Value.String() + } + + results := api.Fetch(requestParams) + + for i, v := range results.Data { + var winner string + + parsedTime, _ := time.Parse(time.RFC3339, v.Date) + formattedTime := parsedTime.Format(config.LayoutUS) + gameNum := strconv.Itoa(i + 1) + home := fmt.Sprintf("%s: %v", v.HomeTeam.Abbreviation, v.HomeTeamScore) + away := fmt.Sprintf("%s: %v", v.VisitorTeam.Abbreviation, v.VisitorTeamScore) + + if v.VisitorTeamScore != 0 || v.HomeTeamScore != 0 { + if v.HomeTeam.ID == config.TeamID { + if v.HomeTeamScore > v.VisitorTeamScore { + winner = v.HomeTeam.FullName + } + } else { + if v.HomeTeamScore < v.VisitorTeamScore { + winner = v.HomeTeam.FullName + } + } + winner = v.VisitorTeam.FullName + } + + game := []string{gameNum, formattedTime, home, away, winner} + table = append(table, game) + } + + tabulate := gotabulate.Create(table) + tabulate.SetHeaders(headers) + fmt.Println(tabulate.Render("simple")) +} diff --git a/handlers/next.go b/handlers/next.go deleted file mode 100644 index 22b2aeb..0000000 --- a/handlers/next.go +++ /dev/null @@ -1,28 +0,0 @@ -package handlers - -import ( - "fmt" - "net/http" - "time" - - "github.com/grahamplata/sixers/api" - "github.com/grahamplata/sixers/config" - "github.com/grahamplata/sixers/utils" - "github.com/spf13/cobra" -) - -// Next handles when the next sixers game is available -func Next(cmd *cobra.Command, args []string) { - // Create the parameters - year := time.Now().Format(config.YearFormat) - url := api.BuildURL(utils.DecrementString(year), year) - - // Do get request and handle the response - response, err := http.Get(url) - if err != nil { - fmt.Printf("The request failed with an error. %s\n", err) - } else { - resp := api.NextResponse(response) - fmt.Println(resp) - } -} diff --git a/handlers/record.go b/handlers/record.go deleted file mode 100644 index 0f5382a..0000000 --- a/handlers/record.go +++ /dev/null @@ -1,29 +0,0 @@ -package handlers - -import ( - "fmt" - "net/http" - "time" - - "github.com/grahamplata/sixers/api" - "github.com/grahamplata/sixers/utils" - "github.com/spf13/cobra" -) - -// Record ... -func Record(cmd *cobra.Command, args []string) { - year := cmd.Flag("year") - var url string - if year.Value.String() == "" { - currentYear := time.Now().Format("2006") - url = api.BuildURL(utils.DecrementString(currentYear), currentYear) - } else { - url = api.BuildURL(year.Value.String(), utils.IncrementString(year.Value.String())) - } - response, err := http.Get(url) - if err != nil { - fmt.Printf("The request failed with error %s\n", err) - } else { - fmt.Println(api.RecordResponse(response)) - } -} diff --git a/handlers/schedule.go b/handlers/schedule.go deleted file mode 100644 index 3ded143..0000000 --- a/handlers/schedule.go +++ /dev/null @@ -1,32 +0,0 @@ -package handlers - -import ( - "fmt" - "net/http" - "time" - - "github.com/grahamplata/sixers/api" - "github.com/grahamplata/sixers/utils" - "github.com/spf13/cobra" -) - -// Schedule ... -func Schedule(cmd *cobra.Command, args []string) { - // Create the parameters - year := cmd.Flag("year") - var url string - if year.Value.String() == "" { - currentYear := time.Now().Format("2006") - url = api.BuildURL(utils.DecrementString(currentYear), currentYear) - } else { - url = api.BuildURL(year.Value.String(), utils.IncrementString(year.Value.String())) - } - // Do get request and handle the response - response, err := http.Get(url) - if err != nil { - fmt.Printf("The request failed with an error. %s\n", err) - } else { - resp := api.ScheduleResponse(response) - fmt.Println(resp) - } -}