|
1 | 1 | using Codebreaker.GameAPIs.Client.Models; |
2 | 2 | using System.Diagnostics; |
| 3 | +using System.Text; |
3 | 4 |
|
4 | 5 | namespace Codebreaker.GameAPIs.Client.Tests; |
5 | 6 |
|
6 | 7 | public class GamesClientTests |
7 | 8 | { |
| 9 | + private readonly ITestOutputHelper? _testOutputHelper; |
| 10 | + |
| 11 | + public GamesClientTests(ITestOutputHelper? testOutputHelper = null) |
| 12 | + { |
| 13 | + _testOutputHelper = testOutputHelper; |
| 14 | + } |
| 15 | + |
8 | 16 | [Fact] |
9 | 17 | public async Task StartGameAsync_Should_ReturnResults() |
10 | 18 | { |
@@ -94,6 +102,146 @@ public async Task GetGamesAsync_Should_ReturnResults() |
94 | 102 | Assert.Equal(2, games.Count()); |
95 | 103 | } |
96 | 104 |
|
| 105 | + [Fact] |
| 106 | + public async Task SetMoveAsync_Should_ReturnResults() |
| 107 | + { |
| 108 | + // Arrange |
| 109 | + (var httpClient, var handlerMock) = GetHttpClientReturningSetMoveSkeleton(); |
| 110 | + |
| 111 | + GamesClient gamesClient = new(httpClient, NullLogger<GamesClient>.Instance); |
| 112 | + |
| 113 | + // Act |
| 114 | + var gameId = Guid.Parse("91f3c729-5e6e-459a-b656-2d77f3f45dd9"); |
| 115 | + var (Results, Ended, IsVictory) = await gamesClient.SetMoveAsync( |
| 116 | + gameId, |
| 117 | + "test", |
| 118 | + GameType.Game6x4, |
| 119 | + 1, |
| 120 | + new[] { "Red", "Green", "Blue", "Yellow" }); |
| 121 | + |
| 122 | + // Assert |
| 123 | + Assert.Equal(2, Results.Length); |
| 124 | + Assert.Equal("White", Results[0]); |
| 125 | + Assert.Equal("White", Results[1]); |
| 126 | + Assert.False(Ended); |
| 127 | + Assert.False(IsVictory); |
| 128 | + |
| 129 | + handlerMock.Protected().Verify( |
| 130 | + "SendAsync", |
| 131 | + Times.Once(), |
| 132 | + ItExpr.IsAny<HttpRequestMessage>(), |
| 133 | + ItExpr.IsAny<CancellationToken>()); |
| 134 | + } |
| 135 | + |
| 136 | + [Fact] |
| 137 | + public async Task GetGameAsync_Should_ReturnResults() |
| 138 | + { |
| 139 | + // Arrange |
| 140 | + (var httpClient, var handlerMock) = GetHttpClientReturningGameSkeleton(); |
| 141 | + |
| 142 | + GamesClient gamesClient = new(httpClient, NullLogger<GamesClient>.Instance); |
| 143 | + |
| 144 | + // Act |
| 145 | + var gameId = Guid.Parse("91f3c729-5e6e-459a-b656-2d77f3f45dd9"); |
| 146 | + var game = await gamesClient.GetGameAsync(gameId); |
| 147 | + |
| 148 | + // Assert |
| 149 | + Assert.NotNull(game); |
| 150 | + Assert.Equal(gameId, game.Id); |
| 151 | + Assert.Equal("Game6x4", game.GameType.ToString()); |
| 152 | + Assert.Equal("test", game.PlayerName); |
| 153 | + Assert.Equal(1, game.LastMoveNumber); |
| 154 | + Assert.Equal(4, game.NumberCodes); |
| 155 | + Assert.Equal(12, game.MaxMoves); |
| 156 | + Assert.False(game.IsVictory); |
| 157 | + |
| 158 | + handlerMock.Protected().Verify( |
| 159 | + "SendAsync", |
| 160 | + Times.Once(), |
| 161 | + ItExpr.IsAny<HttpRequestMessage>(), |
| 162 | + ItExpr.IsAny<CancellationToken>()); |
| 163 | + } |
| 164 | + |
| 165 | + [Fact] |
| 166 | + public async Task CancelGameAsync_Should_CallApi() |
| 167 | + { |
| 168 | + // Arrange |
| 169 | + (var httpClient, var handlerMock) = GetHttpClientForCancelGame(); |
| 170 | + |
| 171 | + GamesClient gamesClient = new(httpClient, NullLogger<GamesClient>.Instance); |
| 172 | + |
| 173 | + // Act |
| 174 | + var gameId = Guid.Parse("91f3c729-5e6e-459a-b656-2d77f3f45dd9"); |
| 175 | + await gamesClient.CancelGameAsync(gameId, "test", GameType.Game6x4); |
| 176 | + |
| 177 | + // Assert |
| 178 | + handlerMock.Protected().Verify( |
| 179 | + "SendAsync", |
| 180 | + Times.Once(), |
| 181 | + ItExpr.IsAny<HttpRequestMessage>(), |
| 182 | + ItExpr.IsAny<CancellationToken>()); |
| 183 | + } |
| 184 | + |
| 185 | + [Fact] |
| 186 | + public async Task CancelGameAsync_Should_TrackActivity() |
| 187 | + { |
| 188 | + // Arrange |
| 189 | + (var httpClient, var handlerMock) = GetHttpClientForCancelGame(); |
| 190 | + bool startActivityReceived = false; |
| 191 | + bool stopActivityReceived = false; |
| 192 | + |
| 193 | + using ActivityListener listener = new() |
| 194 | + { |
| 195 | + ShouldListenTo = _ => true, |
| 196 | + ActivityStarted = activity => |
| 197 | + { |
| 198 | + if (activity.OperationName == "CancelGameAsync") |
| 199 | + { |
| 200 | + startActivityReceived = true; |
| 201 | + Assert.Equal(ActivityKind.Client, activity.Kind); |
| 202 | + } |
| 203 | + }, |
| 204 | + ActivityStopped = activity => |
| 205 | + { |
| 206 | + if (activity.OperationName == "CancelGameAsync") |
| 207 | + { |
| 208 | + stopActivityReceived = true; |
| 209 | + ActivityEvent? gameCanceledEvent = activity.Events.FirstOrDefault(e => e.Name == "GameCanceled"); |
| 210 | + |
| 211 | + // Check if the event exists |
| 212 | + if (gameCanceledEvent != null) |
| 213 | + { |
| 214 | + // Check if there are any tags |
| 215 | + var tags = gameCanceledEvent.Value.Tags; |
| 216 | + foreach (var tag in tags) |
| 217 | + { |
| 218 | + if (tag.Key == "gameId") |
| 219 | + { |
| 220 | + // We found the gameId tag |
| 221 | + Assert.NotNull(tag.Value); |
| 222 | + } |
| 223 | + } |
| 224 | + } |
| 225 | + |
| 226 | + Assert.Equal(ActivityKind.Client, activity.Kind); |
| 227 | + } |
| 228 | + }, |
| 229 | + Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData |
| 230 | + }; |
| 231 | + |
| 232 | + ActivitySource.AddActivityListener(listener); |
| 233 | + |
| 234 | + GamesClient gamesClient = new(httpClient, NullLogger<GamesClient>.Instance); |
| 235 | + |
| 236 | + // Act |
| 237 | + var gameId = Guid.Parse("91f3c729-5e6e-459a-b656-2d77f3f45dd9"); |
| 238 | + await gamesClient.CancelGameAsync(gameId, "test", GameType.Game6x4); |
| 239 | + |
| 240 | + // Assert |
| 241 | + Assert.True(startActivityReceived); |
| 242 | + Assert.True(stopActivityReceived); |
| 243 | + } |
| 244 | + |
97 | 245 | private static (HttpClient Client, Mock<HttpMessageHandler> Handler) GetHttpClientReturningACreatedGameSkeleton() |
98 | 246 | { |
99 | 247 | Mock<IConfiguration> configMock = new(); |
@@ -127,7 +275,7 @@ private static (HttpClient Client, Mock<HttpMessageHandler> Handler) GetHttpClie |
127 | 275 | .ReturnsAsync(new HttpResponseMessage |
128 | 276 | { |
129 | 277 | StatusCode = HttpStatusCode.OK, |
130 | | - Content = new StringContent(returnMessage) |
| 278 | + Content = new StringContent(returnMessage, Encoding.UTF8, "application/json") |
131 | 279 | }).Verifiable(); |
132 | 280 |
|
133 | 281 | return (new(handlerMock.Object) |
@@ -289,7 +437,132 @@ private static (HttpClient Client, Mock<HttpMessageHandler> Handler) GetHttpClie |
289 | 437 | .ReturnsAsync(new HttpResponseMessage |
290 | 438 | { |
291 | 439 | StatusCode = HttpStatusCode.OK, |
292 | | - Content = new StringContent(returnMessage) |
| 440 | + Content = new StringContent(returnMessage, Encoding.UTF8, "application/json") |
| 441 | + }).Verifiable(); |
| 442 | + |
| 443 | + return (new(handlerMock.Object) |
| 444 | + { |
| 445 | + BaseAddress = new Uri(configMock.Object["GameAPIs"] ?? throw new InvalidOperationException()) |
| 446 | + }, handlerMock); |
| 447 | + } |
| 448 | + |
| 449 | + private static (HttpClient Client, Mock<HttpMessageHandler> Handler) GetHttpClientReturningSetMoveSkeleton() |
| 450 | + { |
| 451 | + Mock<IConfiguration> configMock = new(); |
| 452 | + configMock.Setup(x => x[It.IsAny<string>()]).Returns("http://localhost:5000"); |
| 453 | + |
| 454 | + Mock<HttpMessageHandler> handlerMock = new(MockBehavior.Strict); |
| 455 | + string returnMessage = """ |
| 456 | + { |
| 457 | + "id": "91f3c729-5e6e-459a-b656-2d77f3f45dd9", |
| 458 | + "gameType": "Game6x4", |
| 459 | + "moveNumber": 1, |
| 460 | + "ended": false, |
| 461 | + "isVictory": false, |
| 462 | + "results": ["White", "White"] |
| 463 | + } |
| 464 | + """; |
| 465 | + handlerMock.Protected() |
| 466 | + .Setup<Task<HttpResponseMessage>>( |
| 467 | + "SendAsync", |
| 468 | + ItExpr.IsAny<HttpRequestMessage>(), |
| 469 | + ItExpr.IsAny<CancellationToken>()) |
| 470 | + .ReturnsAsync(new HttpResponseMessage |
| 471 | + { |
| 472 | + StatusCode = HttpStatusCode.OK, |
| 473 | + Content = new StringContent(returnMessage, Encoding.UTF8, "application/json") |
| 474 | + }).Verifiable(); |
| 475 | + |
| 476 | + return (new(handlerMock.Object) |
| 477 | + { |
| 478 | + BaseAddress = new Uri(configMock.Object["GameAPIs"] ?? throw new InvalidOperationException()) |
| 479 | + }, handlerMock); |
| 480 | + } |
| 481 | + |
| 482 | + private static (HttpClient Client, Mock<HttpMessageHandler> Handler) GetHttpClientReturningGameSkeleton() |
| 483 | + { |
| 484 | + Mock<IConfiguration> configMock = new(); |
| 485 | + configMock.Setup(x => x[It.IsAny<string>()]).Returns("http://localhost:5000"); |
| 486 | + |
| 487 | + Mock<HttpMessageHandler> handlerMock = new(MockBehavior.Strict); |
| 488 | + string returnMessage = """ |
| 489 | + { |
| 490 | + "id": "91f3c729-5e6e-459a-b656-2d77f3f45dd9", |
| 491 | + "gameType": "Game6x4", |
| 492 | + "playerName": "test", |
| 493 | + "playerIsAuthenticated": false, |
| 494 | + "startTime": "2024-02-14T18:14:49.4420411Z", |
| 495 | + "endTime": null, |
| 496 | + "duration": null, |
| 497 | + "lastMoveNumber": 1, |
| 498 | + "numberCodes": 4, |
| 499 | + "maxMoves": 12, |
| 500 | + "isVictory": false, |
| 501 | + "fieldValues": { |
| 502 | + "colors": [ |
| 503 | + "Red", |
| 504 | + "Green", |
| 505 | + "Blue", |
| 506 | + "Yellow", |
| 507 | + "Purple", |
| 508 | + "Orange" |
| 509 | + ] |
| 510 | + }, |
| 511 | + "codes": [ |
| 512 | + "Yellow", |
| 513 | + "Yellow", |
| 514 | + "Green", |
| 515 | + "Green" |
| 516 | + ], |
| 517 | + "moves": [ |
| 518 | + { |
| 519 | + "id": "963baba8-44b8-45e5-81f3-193959ae5bf6", |
| 520 | + "moveNumber": 1, |
| 521 | + "guessPegs": [ |
| 522 | + "Red", |
| 523 | + "Green", |
| 524 | + "Blue", |
| 525 | + "Yellow" |
| 526 | + ], |
| 527 | + "keyPegs": [ |
| 528 | + "White", |
| 529 | + "White" |
| 530 | + ] |
| 531 | + } |
| 532 | + ] |
| 533 | + } |
| 534 | + """; |
| 535 | + handlerMock.Protected() |
| 536 | + .Setup<Task<HttpResponseMessage>>( |
| 537 | + "SendAsync", |
| 538 | + ItExpr.IsAny<HttpRequestMessage>(), |
| 539 | + ItExpr.IsAny<CancellationToken>()) |
| 540 | + .ReturnsAsync(new HttpResponseMessage |
| 541 | + { |
| 542 | + StatusCode = HttpStatusCode.OK, |
| 543 | + Content = new StringContent(returnMessage, Encoding.UTF8, "application/json") |
| 544 | + }).Verifiable(); |
| 545 | + |
| 546 | + return (new(handlerMock.Object) |
| 547 | + { |
| 548 | + BaseAddress = new Uri(configMock.Object["GameAPIs"] ?? throw new InvalidOperationException()) |
| 549 | + }, handlerMock); |
| 550 | + } |
| 551 | + |
| 552 | + private static (HttpClient Client, Mock<HttpMessageHandler> Handler) GetHttpClientForCancelGame() |
| 553 | + { |
| 554 | + Mock<IConfiguration> configMock = new(); |
| 555 | + configMock.Setup(x => x[It.IsAny<string>()]).Returns("http://localhost:5000"); |
| 556 | + |
| 557 | + Mock<HttpMessageHandler> handlerMock = new(MockBehavior.Strict); |
| 558 | + handlerMock.Protected() |
| 559 | + .Setup<Task<HttpResponseMessage>>( |
| 560 | + "SendAsync", |
| 561 | + ItExpr.IsAny<HttpRequestMessage>(), |
| 562 | + ItExpr.IsAny<CancellationToken>()) |
| 563 | + .ReturnsAsync(new HttpResponseMessage |
| 564 | + { |
| 565 | + StatusCode = HttpStatusCode.OK |
293 | 566 | }).Verifiable(); |
294 | 567 |
|
295 | 568 | return (new(handlerMock.Object) |
|
0 commit comments