1+ using Codebreaker . GameAPIs . Client ;
2+ using Codebreaker . GameAPIs . Client . Models ;
3+ using Moq ;
4+
5+ namespace CodeBreaker . BotWithString . Tests ;
6+
7+ public class StringBotGameRunnerTests
8+ {
9+ [ Fact ]
10+ public async Task PlayGameAsync_Should_StartGameAndMakeMove ( )
11+ {
12+ // Arrange
13+ var mockClient = new Mock < IGamesClient > ( ) ;
14+ var gameId = Guid . NewGuid ( ) ;
15+ var fieldValues = new Dictionary < string , string [ ] >
16+ {
17+ [ "Colors" ] = new [ ] { "Red" , "Blue" , "Green" , "Yellow" }
18+ } ;
19+
20+ mockClient . Setup ( x => x . StartGameAsync ( GameType . Game6x4 , "TestPlayer" , It . IsAny < CancellationToken > ( ) ) )
21+ . ReturnsAsync ( ( gameId , 4 , 12 , fieldValues ) ) ;
22+
23+ mockClient . Setup ( x => x . SetMoveAsync ( gameId , "TestPlayer" , GameType . Game6x4 , 1 ,
24+ It . IsAny < string [ ] > ( ) , It . IsAny < CancellationToken > ( ) ) )
25+ . ReturnsAsync ( ( new [ ] { "4" , "0" } , true , true ) ) ; // 4 black hits = win
26+
27+ var runner = new StringBotGameRunner ( mockClient . Object ) ;
28+
29+ // Act
30+ var result = await runner . PlayGameAsync ( GameType . Game6x4 , "TestPlayer" ) ;
31+
32+ // Assert
33+ Assert . Equal ( gameId , result . GameId ) ;
34+ Assert . Equal ( GameType . Game6x4 , result . GameType ) ;
35+ Assert . Equal ( "TestPlayer" , result . PlayerName ) ;
36+ Assert . True ( result . GameWon ) ;
37+ Assert . True ( result . GameEnded ) ;
38+ Assert . Equal ( 1 , result . MovesUsed ) ;
39+ Assert . NotNull ( result . WinningCombination ) ;
40+ Assert . Equal ( 4 , result . WinningCombination . Length ) ;
41+ }
42+
43+ [ Fact ]
44+ public async Task PlayGameAsync_Should_HandleMultipleMoves ( )
45+ {
46+ // Arrange
47+ var mockClient = new Mock < IGamesClient > ( ) ;
48+ var gameId = Guid . NewGuid ( ) ;
49+ var fieldValues = new Dictionary < string , string [ ] >
50+ {
51+ [ "Colors" ] = new [ ] { "Red" , "Blue" }
52+ } ;
53+
54+ mockClient . Setup ( x => x . StartGameAsync ( GameType . Game6x4 , "TestPlayer" , It . IsAny < CancellationToken > ( ) ) )
55+ . ReturnsAsync ( ( gameId , 4 , 12 , fieldValues ) ) ;
56+
57+ // First move: no matches
58+ mockClient . Setup ( x => x . SetMoveAsync ( gameId , "TestPlayer" , GameType . Game6x4 , 1 ,
59+ It . IsAny < string [ ] > ( ) , It . IsAny < CancellationToken > ( ) ) )
60+ . ReturnsAsync ( ( new [ ] { "0" , "0" } , false , false ) ) ;
61+
62+ // Second move: win
63+ mockClient . Setup ( x => x . SetMoveAsync ( gameId , "TestPlayer" , GameType . Game6x4 , 2 ,
64+ It . IsAny < string [ ] > ( ) , It . IsAny < CancellationToken > ( ) ) )
65+ . ReturnsAsync ( ( new [ ] { "4" , "0" } , true , true ) ) ;
66+
67+ var runner = new StringBotGameRunner ( mockClient . Object ) ;
68+
69+ // Act
70+ var result = await runner . PlayGameAsync ( GameType . Game6x4 , "TestPlayer" ) ;
71+
72+ // Assert
73+ Assert . Equal ( gameId , result . GameId ) ;
74+ Assert . True ( result . GameWon ) ;
75+ Assert . True ( result . GameEnded ) ;
76+ Assert . Equal ( 2 , result . MovesUsed ) ;
77+
78+ // Verify both moves were called
79+ mockClient . Verify ( x => x . SetMoveAsync ( gameId , "TestPlayer" , GameType . Game6x4 , 1 ,
80+ It . IsAny < string [ ] > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Once ) ;
81+ mockClient . Verify ( x => x . SetMoveAsync ( gameId , "TestPlayer" , GameType . Game6x4 , 2 ,
82+ It . IsAny < string [ ] > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Once ) ;
83+ }
84+
85+ [ Fact ]
86+ public async Task PlayGameAsync_Should_HandleGameLoss ( )
87+ {
88+ // Arrange
89+ var mockClient = new Mock < IGamesClient > ( ) ;
90+ var gameId = Guid . NewGuid ( ) ;
91+ var fieldValues = new Dictionary < string , string [ ] >
92+ {
93+ [ "Colors" ] = new [ ] { "Red" , "Blue" }
94+ } ;
95+
96+ mockClient . Setup ( x => x . StartGameAsync ( GameType . Game6x4 , "TestPlayer" , It . IsAny < CancellationToken > ( ) ) )
97+ . ReturnsAsync ( ( gameId , 4 , 2 , fieldValues ) ) ; // Only 2 max moves
98+
99+ // Both moves: no matches, game ends after max moves
100+ mockClient . Setup ( x => x . SetMoveAsync ( gameId , "TestPlayer" , GameType . Game6x4 , It . IsAny < int > ( ) ,
101+ It . IsAny < string [ ] > ( ) , It . IsAny < CancellationToken > ( ) ) )
102+ . ReturnsAsync ( ( new [ ] { "0" , "0" } , false , false ) ) ;
103+
104+ var runner = new StringBotGameRunner ( mockClient . Object ) ;
105+
106+ // Act
107+ var result = await runner . PlayGameAsync ( GameType . Game6x4 , "TestPlayer" ) ;
108+
109+ // Assert
110+ Assert . Equal ( gameId , result . GameId ) ;
111+ Assert . False ( result . GameWon ) ;
112+ Assert . False ( result . GameEnded ) ; // Game didn't officially end, just reached max moves
113+ Assert . Equal ( 2 , result . MovesUsed ) ;
114+ Assert . Null ( result . WinningCombination ) ;
115+ }
116+
117+ [ Fact ]
118+ public async Task PlayGameAsync_Should_HandleGame8x5 ( )
119+ {
120+ // Arrange
121+ var mockClient = new Mock < IGamesClient > ( ) ;
122+ var gameId = Guid . NewGuid ( ) ;
123+ var fieldValues = new Dictionary < string , string [ ] >
124+ {
125+ [ "Colors" ] = new [ ] { "Red" , "Blue" , "Green" , "Yellow" , "Orange" }
126+ } ;
127+
128+ mockClient . Setup ( x => x . StartGameAsync ( GameType . Game8x5 , "TestPlayer" , It . IsAny < CancellationToken > ( ) ) )
129+ . ReturnsAsync ( ( gameId , 5 , 14 , fieldValues ) ) ;
130+
131+ mockClient . Setup ( x => x . SetMoveAsync ( gameId , "TestPlayer" , GameType . Game8x5 , 1 ,
132+ It . IsAny < string [ ] > ( ) , It . IsAny < CancellationToken > ( ) ) )
133+ . ReturnsAsync ( ( new [ ] { "5" , "0" } , true , true ) ) ; // 5 black hits = win
134+
135+ var runner = new StringBotGameRunner ( mockClient . Object ) ;
136+
137+ // Act
138+ var result = await runner . PlayGameAsync ( GameType . Game8x5 , "TestPlayer" ) ;
139+
140+ // Assert
141+ Assert . Equal ( GameType . Game8x5 , result . GameType ) ;
142+ Assert . True ( result . GameWon ) ;
143+ Assert . NotNull ( result . WinningCombination ) ;
144+ Assert . Equal ( 5 , result . WinningCombination . Length ) ;
145+ }
146+ }
0 commit comments