diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index ecae297..ac0840c 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -5,6 +5,7 @@ on:
branches: [ master ]
pull_request:
branches: [ master ]
+ workflow_dispatch:
jobs:
build:
@@ -22,4 +23,22 @@ jobs:
- name: Build
run: dotnet build --no-restore
- name: Test
- run: dotnet test --no-build --verbosity normal
+ run: dotnet test --no-build --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage
+ - name: Code Coverage Report
+ uses: irongut/CodeCoverageSummary@v1.3.0
+ with:
+ filename: coverage/**/coverage.cobertura.xml
+ badge: true
+ fail_below_min: false
+ format: markdown
+ hide_branch_rate: false
+ hide_complexity: true
+ indicators: true
+ output: both
+ thresholds: '60 80'
+ - name: Add Coverage PR Comment
+ uses: marocchino/sticky-pull-request-comment@v2
+ if: github.event_name == 'pull_request'
+ with:
+ recreate: true
+ path: code-coverage-results.md
\ No newline at end of file
diff --git a/BaseballSharp.sln b/BaseballSharp.sln
index a0dcc65..ac49907 100644
--- a/BaseballSharp.sln
+++ b/BaseballSharp.sln
@@ -15,7 +15,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BaseballSharpCli", "samples
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BaseballSharp", "src\BaseballSharp.csproj", "{B188B5BF-0708-4F12-BD6A-3A0664BE9172}"
EndProject
-Global
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseballSharp.Test", "test\BaseballSharp.Test\BaseballSharp.Test.csproj", "{DB0661A1-F7C0-4D43-8BE3-DF66BF9FAF4A}"
+EndProject
+Global5206EC59-0954-4355-B48B-B014E0E79032
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
@@ -29,6 +31,10 @@ Global
{B188B5BF-0708-4F12-BD6A-3A0664BE9172}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B188B5BF-0708-4F12-BD6A-3A0664BE9172}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B188B5BF-0708-4F12-BD6A-3A0664BE9172}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DB0661A1-F7C0-4D43-8BE3-DF66BF9FAF4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DB0661A1-F7C0-4D43-8BE3-DF66BF9FAF4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DB0661A1-F7C0-4D43-8BE3-DF66BF9FAF4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DB0661A1-F7C0-4D43-8BE3-DF66BF9FAF4A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/MLBClient.cs b/src/MLBClient.cs
index 2a406b4..497a1b7 100644
--- a/src/MLBClient.cs
+++ b/src/MLBClient.cs
@@ -8,10 +8,13 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
+using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Threading.Tasks;
using Team = BaseballSharp.DTO.Teams.Team;
+[assembly: InternalsVisibleTo("BaseballSharp.Test")]
+
namespace BaseballSharp
{
///
@@ -19,10 +22,18 @@ namespace BaseballSharp
///
public class MLBClient : IMLBClient
{
- private static HttpClient _httpClient = new HttpClient();
+ private HttpClient _httpClient = new HttpClient();
private static readonly string _baseUrl = "https://statsapi.mlb.com/api/v1";
private static readonly short _outsInCompletedInning = 3;
+ internal HttpClient HttpClient
+ {
+ set
+ {
+ _httpClient = value;
+ }
+ }
+
private async Task GetResponseAsync(string endpoint)
{
@@ -52,6 +63,7 @@ public async Task> GetScheduleAsync(DateTime date)
gameID = game.gamePk,
AwayTeam = game.teams?.away?.team?.name,
HomeTeam = game.teams?.home?.team?.name,
+ Ballpark = game.venue?.name,
ScheduledInnings = game.scheduledInnings,
StatusCode = Schedule.GetStatusCode(game.status?.statusCode)
});
@@ -111,7 +123,8 @@ public async Task> GetPitchingReportsAsync(DateTime
{
teamsList.Add(new Models.Team()
{
- Name = team.name,
+ FullName = team.name,
+ Name = team.teamName,
Location = team.locationName,
Id = team.id,
LeagueId = team.league?.id,
diff --git a/test/BaseballSharp.Test/BaseballSharp.Test.csproj b/test/BaseballSharp.Test/BaseballSharp.Test.csproj
new file mode 100644
index 0000000..d5541df
--- /dev/null
+++ b/test/BaseballSharp.Test/BaseballSharp.Test.csproj
@@ -0,0 +1,36 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
diff --git a/test/BaseballSharp.Test/GlobalUsings.cs b/test/BaseballSharp.Test/GlobalUsings.cs
new file mode 100644
index 0000000..8c927eb
--- /dev/null
+++ b/test/BaseballSharp.Test/GlobalUsings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/test/BaseballSharp.Test/MLBClientShould.cs b/test/BaseballSharp.Test/MLBClientShould.cs
new file mode 100644
index 0000000..db3cfe5
--- /dev/null
+++ b/test/BaseballSharp.Test/MLBClientShould.cs
@@ -0,0 +1,94 @@
+
+using System.Net;
+using Moq;
+using Moq.Protected;
+
+namespace BaseballSharp.Test
+{
+ public class MLBClientShould
+ {
+ private HttpClient BuildMockedHttpClient(string returnContent)
+ {
+ var handlerMock = new Mock(MockBehavior.Strict);
+
+ handlerMock
+ .Protected()
+ // Setup the PROTECTED method to mock
+ .Setup>(
+ "SendAsync",
+ ItExpr.IsAny(),
+ ItExpr.IsAny()
+ )
+ // Prepare the expected response of the mocked HttpClient
+ .ReturnsAsync(new HttpResponseMessage()
+ {
+ StatusCode = HttpStatusCode.OK,
+ Content = new StringContent(returnContent),
+ })
+ .Verifiable();
+
+ return new HttpClient(handlerMock.Object);
+ }
+
+ [Fact]
+ public async void ReturnAScheduleGivenAValidDate()
+ {
+ var sut = new MLBClient
+ {
+ HttpClient = BuildMockedHttpClient(File.ReadAllText("Schedule.json")),
+ };
+
+ var game = (await sut.GetScheduleAsync(DateTime.Now)).ToList().Single();
+
+ Assert.Equal("Toronto Blue Jays", game.AwayTeam);
+ Assert.Equal("Comerica Park", game.Ballpark);
+ Assert.Equal(746470, game.gameID);
+ Assert.Equal("Detroit Tigers", game.HomeTeam);
+ Assert.Equal(9, game.ScheduledInnings);
+ Assert.Equal(Enums.GameStatus.PreGame, game.StatusCode);
+ }
+
+ [Fact]
+ public async void ReturnAValidPitchingReportGivenAValidDate()
+ {
+ var sut = new MLBClient
+ {
+ HttpClient = BuildMockedHttpClient(File.ReadAllText("PitchingReports.json")),
+ };
+
+ var pitchingReport = (await sut.GetPitchingReportsAsync(DateTime.Now)).ToList().Single();
+
+ Assert.Equal(607192, pitchingReport.AwayProbablePitcherId);
+ Assert.Equal("Tyler Glasnow", pitchingReport.AwayProbablePitcherName);
+ Assert.Equal("", pitchingReport.AwayProbablePitcherNotes);
+ Assert.Equal("Los Angeles Dodgers", pitchingReport.AwayTeam);
+ Assert.Equal(656731, pitchingReport.HomeProbablePitcherId);
+ Assert.Equal("Tylor Megill", pitchingReport.HomeProbablePitcherName);
+ Assert.Equal("", pitchingReport.HomeProbablePitcherNotes);
+ Assert.Equal("New York Mets", pitchingReport.HomeTeam);
+ }
+
+ [Fact]
+ public async void ReturnValidTeamData()
+ {
+ var sut = new MLBClient
+ {
+ HttpClient = BuildMockedHttpClient(File.ReadAllText("TeamData.json")),
+ };
+
+ var teamData = (await sut.GetTeamDataAsync()).ToList().Single();
+
+ Assert.Equal("OAK", teamData.Abbreviation);
+ Assert.Equal(200, teamData.DivisionId);
+ Assert.Equal("American League West", teamData.DivisionName);
+ Assert.Equal("Oakland Athletics", teamData.FullName);
+ Assert.Equal(133, teamData.Id);
+ Assert.Equal(103, teamData.LeagueId);
+ Assert.Equal("American League", teamData.LeagueName);
+ Assert.Equal("Oakland", teamData.Location);
+ Assert.Equal("Athletics", teamData.Name);
+ Assert.Equal(10, teamData.VenueId);
+ Assert.Equal("Oakland Coliseum", teamData.VenueName);
+ }
+ }
+}
diff --git a/test/BaseballSharp.Test/PitchingReports.json b/test/BaseballSharp.Test/PitchingReports.json
new file mode 100644
index 0000000..fd3539a
--- /dev/null
+++ b/test/BaseballSharp.Test/PitchingReports.json
@@ -0,0 +1,38 @@
+{
+ "dates": [
+ {
+ "date": "2024-05-28",
+ "games": [
+ {
+ "gamePk": 745818,
+ "gameDate": "2024-05-28T20:10:00Z",
+ "status": {
+ "abstractGameState": "Final"
+ },
+ "teams": {
+ "away": {
+ "team": {
+ "id": 119,
+ "name": "Los Angeles Dodgers"
+ },
+ "probablePitcher": {
+ "id": 607192,
+ "fullName": "Tyler Glasnow"
+ }
+ },
+ "home": {
+ "team": {
+ "id": 121,
+ "name": "New York Mets"
+ },
+ "probablePitcher": {
+ "id": 656731,
+ "fullName": "Tylor Megill"
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/BaseballSharp.Test/Schedule.json b/test/BaseballSharp.Test/Schedule.json
new file mode 100644
index 0000000..8078ec1
--- /dev/null
+++ b/test/BaseballSharp.Test/Schedule.json
@@ -0,0 +1,93 @@
+{
+ "copyright": "Copyright 2024 MLB Advanced Media, L.P. Use of any content on this page acknowledges agreement to the terms posted here http://gdx.mlb.com/components/copyright.txt",
+ "totalItems": 15,
+ "totalEvents": 0,
+ "totalGames": 15,
+ "totalGamesInProgress": 0,
+ "dates": [
+ {
+ "date": "2024-05-25",
+ "totalItems": 15,
+ "totalEvents": 0,
+ "totalGames": 15,
+ "totalGamesInProgress": 0,
+ "games": [
+ {
+ "gamePk": 746470,
+ "gameGuid": "02f1258c-fe62-41ae-ab53-374dec7bca3d",
+ "link": "/api/v1.1/game/746470/feed/live",
+ "gameType": "R",
+ "season": "2024",
+ "gameDate": "2024-05-25T17:10:00Z",
+ "officialDate": "2024-05-25",
+ "status": {
+ "abstractGameState": "Preview",
+ "codedGameState": "P",
+ "detailedState": "Pre-Game",
+ "statusCode": "P",
+ "startTimeTBD": false,
+ "abstractGameCode": "P"
+ },
+ "teams": {
+ "away": {
+ "leagueRecord": {
+ "wins": 23,
+ "losses": 27,
+ "pct": ".460"
+ },
+ "score": 0,
+ "team": {
+ "id": 141,
+ "name": "Toronto Blue Jays",
+ "link": "/api/v1/teams/141"
+ },
+ "splitSquad": false,
+ "seriesNumber": 17
+ },
+ "home": {
+ "leagueRecord": {
+ "wins": 24,
+ "losses": 27,
+ "pct": ".471"
+ },
+ "score": 0,
+ "team": {
+ "id": 116,
+ "name": "Detroit Tigers",
+ "link": "/api/v1/teams/116"
+ },
+ "splitSquad": false,
+ "seriesNumber": 17
+ }
+ },
+ "venue": {
+ "id": 2394,
+ "name": "Comerica Park",
+ "link": "/api/v1/venues/2394"
+ },
+ "content": {
+ "link": "/api/v1/game/746470/content"
+ },
+ "gameNumber": 1,
+ "publicFacing": true,
+ "doubleHeader": "N",
+ "gamedayType": "P",
+ "tiebreaker": "N",
+ "calendarEventID": "14-746470-2024-05-25",
+ "seasonDisplay": "2024",
+ "dayNight": "day",
+ "scheduledInnings": 9,
+ "reverseHomeAwayStatus": false,
+ "inningBreakLength": 120,
+ "gamesInSeries": 4,
+ "seriesGameNumber": 3,
+ "seriesDescription": "Regular Season",
+ "recordSource": "S",
+ "ifNecessary": "N",
+ "ifNecessaryDescription": "Normal Game"
+ }
+ ],
+ "events": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/BaseballSharp.Test/TeamData.json b/test/BaseballSharp.Test/TeamData.json
new file mode 100644
index 0000000..5deaf1c
--- /dev/null
+++ b/test/BaseballSharp.Test/TeamData.json
@@ -0,0 +1,52 @@
+{
+ "copyright": "Copyright 2024 MLB Advanced Media, L.P. Use of any content on this page acknowledges agreement to the terms posted here http://gdx.mlb.com/components/copyright.txt",
+ "teams": [
+ {
+ "springLeague": {
+ "id": 114,
+ "name": "Cactus League",
+ "link": "/api/v1/league/114",
+ "abbreviation": "CL"
+ },
+ "allStarStatus": "N",
+ "id": 133,
+ "name": "Oakland Athletics",
+ "link": "/api/v1/teams/133",
+ "season": 2024,
+ "venue": {
+ "id": 10,
+ "name": "Oakland Coliseum",
+ "link": "/api/v1/venues/10"
+ },
+ "springVenue": {
+ "id": 2507,
+ "link": "/api/v1/venues/2507"
+ },
+ "teamCode": "oak",
+ "fileCode": "oak",
+ "abbreviation": "OAK",
+ "teamName": "Athletics",
+ "locationName": "Oakland",
+ "firstYearOfPlay": "1901",
+ "league": {
+ "id": 103,
+ "name": "American League",
+ "link": "/api/v1/league/103"
+ },
+ "division": {
+ "id": 200,
+ "name": "American League West",
+ "link": "/api/v1/divisions/200"
+ },
+ "sport": {
+ "id": 1,
+ "link": "/api/v1/sports/1",
+ "name": "Major League Baseball"
+ },
+ "shortName": "Oakland",
+ "franchiseName": "Oakland",
+ "clubName": "Athletics",
+ "active": true
+ }
+ ]
+}
\ No newline at end of file