Skip to content

Commit 26f2a33

Browse files
Add unit tests for Rock Paper Scissors game logic and score handling
1 parent 9aeff67 commit 26f2a33

1 file changed

Lines changed: 189 additions & 0 deletions

File tree

internal/rockpaperscissors/rockpaperscissors_test.go

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package rockpaperscissors
22

33
import (
4+
"fmt"
45
"testing"
56
)
67

@@ -222,3 +223,191 @@ func TestGame_isGameOver(t *testing.T) {
222223
})
223224
}
224225
}
226+
227+
func TestGame_updateScore(t *testing.T) {
228+
tests := []struct {
229+
name string
230+
winner string
231+
wantPlayerScore int
232+
wantComputerScore int
233+
}{
234+
{
235+
name: "Player wins",
236+
winner: "player",
237+
wantPlayerScore: 1,
238+
wantComputerScore: 0,
239+
},
240+
{
241+
name: "Computer wins",
242+
winner: "computer",
243+
wantPlayerScore: 0,
244+
wantComputerScore: 1,
245+
},
246+
{
247+
name: "Draw",
248+
winner: "draw",
249+
wantPlayerScore: 0,
250+
wantComputerScore: 0,
251+
},
252+
}
253+
for _, tt := range tests {
254+
t.Run(tt.name, func(t *testing.T) {
255+
g := &Game{
256+
Winner: tt.winner,
257+
}
258+
g.updateScore()
259+
if g.PlayerScore != tt.wantPlayerScore {
260+
t.Errorf("updateScore() PlayerScore = %v, want %v", g.PlayerScore, tt.wantPlayerScore)
261+
}
262+
if g.ComputerScore != tt.wantComputerScore {
263+
t.Errorf("updateScore() ComputerScore = %v, want %v", g.ComputerScore, tt.wantComputerScore)
264+
}
265+
})
266+
}
267+
}
268+
269+
func TestGame_getGameOverMessage(t *testing.T) {
270+
tests := []struct {
271+
name string
272+
playerScore int
273+
computerScore int
274+
wantMsgContains string
275+
}{
276+
{
277+
name: "Player wins",
278+
playerScore: 2,
279+
computerScore: 1,
280+
wantMsgContains: "You win the match",
281+
},
282+
{
283+
name: "Computer wins",
284+
playerScore: 1,
285+
computerScore: 2,
286+
wantMsgContains: "Computer wins the match",
287+
},
288+
{
289+
name: "Draw",
290+
playerScore: 1,
291+
computerScore: 1,
292+
wantMsgContains: "The match is a draw",
293+
},
294+
}
295+
for _, tt := range tests {
296+
t.Run(tt.name, func(t *testing.T) {
297+
g := &Game{
298+
PlayerScore: tt.playerScore,
299+
ComputerScore: tt.computerScore,
300+
}
301+
got := g.getGameOverMessage()
302+
if got == "" {
303+
t.Error("getGameOverMessage() returned empty string")
304+
}
305+
if !contains(got, tt.wantMsgContains) {
306+
t.Errorf("getGameOverMessage() = %v, want it to contain %v", got, tt.wantMsgContains)
307+
}
308+
})
309+
}
310+
}
311+
312+
// MockPrompter implements the Prompter interface for testing
313+
type MockPrompter struct {
314+
selectReturn int
315+
selectError error
316+
}
317+
318+
func (m *MockPrompter) Select(prompt, defaultValue string, options []string) (int, error) {
319+
return m.selectReturn, m.selectError
320+
}
321+
322+
type mockPromptSequence struct {
323+
returns []int
324+
errors []error
325+
index int
326+
}
327+
328+
func (m *mockPromptSequence) Select(prompt, defaultValue string, options []string) (int, error) {
329+
if m.index >= len(m.returns) {
330+
return 0, nil
331+
}
332+
ret := m.returns[m.index]
333+
err := m.errors[m.index]
334+
m.index++
335+
return ret, err
336+
}
337+
338+
func TestPlayGame(t *testing.T) {
339+
tests := []struct {
340+
name string
341+
prompter Prompter
342+
wantGameOver bool
343+
}{
344+
{
345+
name: "Complete game sequence",
346+
prompter: &mockPromptSequence{
347+
returns: []int{1, 0, 0, 0}, // Select 5 rounds, then rock three times
348+
errors: []error{nil, nil, nil, nil},
349+
},
350+
wantGameOver: true,
351+
},
352+
{
353+
name: "Error on rounds selection",
354+
prompter: &mockPromptSequence{
355+
returns: []int{0},
356+
errors: []error{fmt.Errorf("mock error")},
357+
},
358+
wantGameOver: true,
359+
},
360+
{
361+
name: "Error on move selection",
362+
prompter: &mockPromptSequence{
363+
returns: []int{0, 0},
364+
errors: []error{nil, fmt.Errorf("mock error")},
365+
},
366+
wantGameOver: true,
367+
},
368+
{
369+
name: "Invalid round index",
370+
prompter: &mockPromptSequence{
371+
returns: []int{99, 3}, // Invalid round index, then exit
372+
errors: []error{nil, nil},
373+
},
374+
wantGameOver: true,
375+
},
376+
}
377+
378+
for _, tt := range tests {
379+
t.Run(tt.name, func(t *testing.T) {
380+
PlayGame(tt.prompter)
381+
})
382+
}
383+
}
384+
385+
func TestParseInt(t *testing.T) {
386+
tests := []struct {
387+
name string
388+
input string
389+
want int
390+
}{
391+
{
392+
name: "Valid number",
393+
input: "5",
394+
want: 5,
395+
},
396+
{
397+
name: "Invalid input returns default",
398+
input: "invalid",
399+
want: 3,
400+
},
401+
}
402+
for _, tt := range tests {
403+
t.Run(tt.name, func(t *testing.T) {
404+
if got := parseInt(tt.input); got != tt.want {
405+
t.Errorf("parseInt() = %v, want %v", got, tt.want)
406+
}
407+
})
408+
}
409+
}
410+
411+
func contains(s, substr string) bool {
412+
return len(s) >= len(substr) && s[0:len(substr)] == substr
413+
}

0 commit comments

Comments
 (0)