-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquiz_lib_test.cpp
More file actions
142 lines (115 loc) · 5.22 KB
/
Copy pathquiz_lib_test.cpp
File metadata and controls
142 lines (115 loc) · 5.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// quiz_lib_test.cpp — Unit tests for quiz_lib using GoogleTest 1.8.1
//
// Test strategy:
// - All tests are pure (no I/O, no global state mutation) so they can run
// in any order and in parallel.
// - We use a seeded `generate_question` to get deterministic inputs,
// making failures easy to reproduce without mocking a random source.
// - Test names follow the pattern:
// TEST(<TypeUnderTest>, <WhatIsBeingVerified>)
#include <gtest/gtest.h>
#include "quiz.hpp" // quiz::Question, generate_question, check_answer, Score
// ── quiz::generate_question ───────────────────────────────────────────────────
// The same seed must always produce the same question. This property is
// critical: tests that snapshot a "correct" answer depend on it.
TEST(GenerateQuestion, SameSeedGivesSameQuestion) {
quiz::Question q1 = quiz::generate_question(0);
quiz::Question q2 = quiz::generate_question(0);
EXPECT_EQ(q1.a, q2.a);
EXPECT_EQ(q1.b, q2.b);
EXPECT_EQ(q1.correct, q2.correct);
}
// Different seeds must produce different questions (at least for the first few
// seeds — the sequence cycles after 144 unique combinations).
TEST(GenerateQuestion, DifferentSeedsGiveDifferentQuestions) {
quiz::Question q0 = quiz::generate_question(0);
quiz::Question q1 = quiz::generate_question(1);
// At minimum, `a` or `b` should differ.
EXPECT_FALSE(q0.a == q1.a && q0.b == q1.b)
<< "seed 0 and seed 1 produced identical operands";
}
// Operands must stay within the traditional times-table range [1, 12].
TEST(GenerateQuestion, OperandsAreInRange) {
for (int seed = 0; seed < 50; ++seed) {
quiz::Question q = quiz::generate_question(seed);
EXPECT_GE(q.a, 1) << "a out of range for seed " << seed;
EXPECT_LE(q.a, 12) << "a out of range for seed " << seed;
EXPECT_GE(q.b, 1) << "b out of range for seed " << seed;
EXPECT_LE(q.b, 12) << "b out of range for seed " << seed;
}
}
// The pre-computed `correct` field must equal a * b.
TEST(GenerateQuestion, CorrectAnswerEqualsProduct) {
for (int seed = 0; seed < 50; ++seed) {
quiz::Question q = quiz::generate_question(seed);
EXPECT_EQ(q.correct, q.a * q.b)
<< "correct != a*b for seed " << seed;
}
}
// The prompt string must mention both operands (human-readable sanity check).
TEST(GenerateQuestion, PromptContainsBothOperands) {
quiz::Question q = quiz::generate_question(0); // 1 × 1
std::string prompt = q.prompt();
EXPECT_NE(prompt.find(std::to_string(q.a)), std::string::npos)
<< "prompt does not contain operand a";
EXPECT_NE(prompt.find(std::to_string(q.b)), std::string::npos)
<< "prompt does not contain operand b";
}
// ── quiz::check_answer ────────────────────────────────────────────────────────
// check_answer must return true when the player's answer equals a * b.
TEST(CheckAnswer, ReturnsTrue_WhenAnswerIsCorrect) {
quiz::Question q = quiz::generate_question(5); // some fixed question
EXPECT_TRUE(quiz::check_answer(q, q.correct));
}
// check_answer must return false for an obviously wrong answer.
TEST(CheckAnswer, ReturnsFalse_WhenAnswerIsWrong) {
quiz::Question q = quiz::generate_question(5);
// q.correct + 1 is always wrong (products are positive integers).
EXPECT_FALSE(quiz::check_answer(q, q.correct + 1));
}
// Zero is only correct if one of the operands is zero — which cannot happen
// because operands are in [1, 12]. So check_answer(q, 0) is always false.
TEST(CheckAnswer, ReturnsFalse_ForZero) {
quiz::Question q = quiz::generate_question(7);
EXPECT_FALSE(quiz::check_answer(q, 0));
}
// ── quiz::Score ───────────────────────────────────────────────────────────────
TEST(Score, InitialCountsAreZero) {
quiz::Score s;
EXPECT_EQ(s.correct_count(), 0);
EXPECT_EQ(s.total_count(), 0);
}
TEST(Score, RecordCorrect_IncrementsBoothCounters) {
quiz::Score s;
s.record(true);
EXPECT_EQ(s.correct_count(), 1);
EXPECT_EQ(s.total_count(), 1);
}
TEST(Score, RecordIncorrect_IncrementsTotalOnly) {
quiz::Score s;
s.record(false);
EXPECT_EQ(s.correct_count(), 0);
EXPECT_EQ(s.total_count(), 1);
}
TEST(Score, MixedRecords_TallyCorrectly) {
quiz::Score s;
s.record(true);
s.record(false);
s.record(true);
s.record(true);
EXPECT_EQ(s.correct_count(), 3);
EXPECT_EQ(s.total_count(), 4);
}
// The summary string should contain the correct and total counts so callers
// can parse or display them without re-computing.
TEST(Score, SummaryContainsCorrectAndTotal) {
quiz::Score s;
s.record(true);
s.record(false);
s.record(true); // 2/3
std::string summary = s.summary();
EXPECT_NE(summary.find("2"), std::string::npos)
<< "summary does not mention correct count";
EXPECT_NE(summary.find("3"), std::string::npos)
<< "summary does not mention total count";
}