1+ #include < gtest/gtest.h>
2+ #include < sstream>
3+ #include < iostream>
4+ #include " Logger.hpp"
5+ #include " GameStats.hpp"
6+
7+ // Test fixture for Logger tests that can capture output
8+ class LoggerTest : public ::testing::Test {
9+ protected:
10+ void SetUp () override {
11+ // Save original stream buffers
12+ original_cout = std::cout.rdbuf ();
13+ original_cerr = std::cerr.rdbuf ();
14+
15+ // Redirect cout and cerr to our string streams
16+ std::cout.rdbuf (cout_buffer.rdbuf ());
17+ std::cerr.rdbuf (cerr_buffer.rdbuf ());
18+ }
19+
20+ void TearDown () override {
21+ // Restore original stream buffers
22+ std::cout.rdbuf (original_cout);
23+ std::cerr.rdbuf (original_cerr);
24+ }
25+
26+ std::stringstream cout_buffer;
27+ std::stringstream cerr_buffer;
28+ std::streambuf* original_cout;
29+ std::streambuf* original_cerr;
30+ };
31+
32+ // Test LogLevel enum values
33+ TEST_F (LoggerTest, LogLevelEnumValues) {
34+ EXPECT_EQ (static_cast <int >(LogLevel::ERROR), 0 );
35+ EXPECT_EQ (static_cast <int >(LogLevel::WARNING), 1 );
36+ EXPECT_EQ (static_cast <int >(LogLevel::INFO), 2 );
37+ EXPECT_EQ (static_cast <int >(LogLevel::DEBUG), 3 );
38+ }
39+
40+ // Test basic log functionality with different levels
41+ TEST_F (LoggerTest, BasicLogFunctionality) {
42+ Logger::log (LogLevel::INFO, " Test info message" );
43+ std::string output = cout_buffer.str ();
44+ EXPECT_TRUE (output.find (" [INFO] Test info message" ) != std::string::npos);
45+
46+ cout_buffer.str (" " ); // Clear buffer
47+ cout_buffer.clear ();
48+
49+ Logger::log (LogLevel::DEBUG, " Test debug message" );
50+ output = cout_buffer.str ();
51+ EXPECT_TRUE (output.find (" [DEBUG] Test debug message" ) != std::string::npos);
52+ }
53+
54+ // Test error and warning messages go to stderr
55+ TEST_F (LoggerTest, ErrorWarningToStderr) {
56+ Logger::log (LogLevel::ERROR, " Test error message" );
57+ std::string error_output = cerr_buffer.str ();
58+ EXPECT_TRUE (error_output.find (" [ERROR] Test error message" ) != std::string::npos);
59+ EXPECT_TRUE (cout_buffer.str ().empty ()); // Should not appear in cout
60+
61+ cerr_buffer.str (" " ); // Clear buffer
62+ cerr_buffer.clear ();
63+
64+ Logger::log (LogLevel::WARNING, " Test warning message" );
65+ error_output = cerr_buffer.str ();
66+ EXPECT_TRUE (error_output.find (" [WARN] Test warning message" ) != std::string::npos);
67+ EXPECT_TRUE (cout_buffer.str ().empty ()); // Should not appear in cout
68+ }
69+
70+ // Test convenience methods
71+ TEST_F (LoggerTest, ConvenienceMethods) {
72+ Logger::error (" Error via convenience method" );
73+ std::string error_output = cerr_buffer.str ();
74+ EXPECT_TRUE (error_output.find (" [ERROR] Error via convenience method" ) != std::string::npos);
75+
76+ cerr_buffer.str (" " );
77+ cerr_buffer.clear ();
78+
79+ Logger::warning (" Warning via convenience method" );
80+ error_output = cerr_buffer.str ();
81+ EXPECT_TRUE (error_output.find (" [WARN] Warning via convenience method" ) != std::string::npos);
82+
83+ Logger::info (" Info via convenience method" );
84+ std::string info_output = cout_buffer.str ();
85+ EXPECT_TRUE (info_output.find (" [INFO] Info via convenience method" ) != std::string::npos);
86+
87+ cout_buffer.str (" " );
88+ cout_buffer.clear ();
89+
90+ Logger::debug (" Debug via convenience method" );
91+ info_output = cout_buffer.str ();
92+ EXPECT_TRUE (info_output.find (" [DEBUG] Debug via convenience method" ) != std::string::npos);
93+ }
94+
95+ // Test logObject template method
96+ TEST_F (LoggerTest, LogObjectTemplate) {
97+ // Test with integer
98+ Logger::logObject (LogLevel::INFO, 42 );
99+ std::string output = cout_buffer.str ();
100+ EXPECT_TRUE (output.find (" [INFO] 42" ) != std::string::npos);
101+
102+ cout_buffer.str (" " );
103+ cout_buffer.clear ();
104+
105+ // Test with double
106+ Logger::logObject (LogLevel::DEBUG, 3.14159 );
107+ output = cout_buffer.str ();
108+ EXPECT_TRUE (output.find (" [DEBUG] 3.14159" ) != std::string::npos);
109+
110+ cout_buffer.str (" " );
111+ cout_buffer.clear ();
112+
113+ // Test with string
114+ std::string test_string = " Hello World" ;
115+ Logger::logObject (LogLevel::INFO, test_string);
116+ output = cout_buffer.str ();
117+ EXPECT_TRUE (output.find (" [INFO] Hello World" ) != std::string::npos);
118+ }
119+
120+ // Test logObject with GameStats (assuming it has operator<< overloaded)
121+ TEST_F (LoggerTest, LogObjectWithGameStats) {
122+ GameStats stats (100 , 5 , 8 , 2 );
123+ Logger::logObject (LogLevel::INFO, stats);
124+ std::string output = cout_buffer.str ();
125+
126+ // Should contain the formatted GameStats output
127+ EXPECT_TRUE (output.find (" [INFO]" ) != std::string::npos);
128+ EXPECT_TRUE (output.find (" Final Stats" ) != std::string::npos);
129+ EXPECT_TRUE (output.find (" Score: 100" ) != std::string::npos);
130+ }
131+
132+ // Test empty message handling
133+ TEST_F (LoggerTest, EmptyMessage) {
134+ Logger::log (LogLevel::INFO, " " );
135+ std::string output = cout_buffer.str ();
136+ EXPECT_TRUE (output.find (" [INFO]" ) != std::string::npos);
137+
138+ Logger::info (" " );
139+ cout_buffer.str (" " );
140+ cout_buffer.clear ();
141+
142+ Logger::info (" " );
143+ output = cout_buffer.str ();
144+ EXPECT_TRUE (output.find (" [INFO]" ) != std::string::npos);
145+ }
146+
147+ // Test message with special characters
148+ TEST_F (LoggerTest, SpecialCharacters) {
149+ Logger::info (" Message with newlines\n and tabs\t and symbols!@#$%" );
150+ std::string output = cout_buffer.str ();
151+ EXPECT_TRUE (output.find (" [INFO] Message with newlines\n and tabs\t and symbols!@#$%" ) != std::string::npos);
152+ }
153+
154+ // Test very long message
155+ TEST_F (LoggerTest, LongMessage) {
156+ std::string long_message (1000 , ' A' );
157+ Logger::info (long_message);
158+ std::string output = cout_buffer.str ();
159+ EXPECT_TRUE (output.find (" [INFO] " + long_message) != std::string::npos);
160+ }
161+
162+ // Test multiple consecutive log calls
163+ TEST_F (LoggerTest, MultipleLogCalls) {
164+ Logger::info (" First message" );
165+ Logger::warning (" Second message" );
166+ Logger::debug (" Third message" );
167+
168+ std::string cout_output = cout_buffer.str ();
169+ std::string cerr_output = cerr_buffer.str ();
170+
171+ // Info and debug should be in cout
172+ EXPECT_TRUE (cout_output.find (" [INFO] First message" ) != std::string::npos);
173+ EXPECT_TRUE (cout_output.find (" [DEBUG] Third message" ) != std::string::npos);
174+
175+ // Warning should be in cerr
176+ EXPECT_TRUE (cerr_output.find (" [WARN] Second message" ) != std::string::npos);
177+ }
178+
179+ // Test SDL error logging methods (these will test the method structure,
180+ // but won't test actual SDL errors since SDL may not be initialized in tests)
181+ TEST_F (LoggerTest, SDLErrorLoggingMethods) {
182+ // These methods will call SDL_GetError() etc., but in a test environment
183+ // they might return empty strings or default error messages
184+
185+ Logger::logSDLError (LogLevel::ERROR, " SDL initialization failed" );
186+ std::string error_output = cerr_buffer.str ();
187+ EXPECT_TRUE (error_output.find (" [ERROR] SDL initialization failed:" ) != std::string::npos);
188+
189+ cerr_buffer.str (" " );
190+ cerr_buffer.clear ();
191+
192+ Logger::logSDLImageError (LogLevel::WARNING, " Image loading failed" );
193+ error_output = cerr_buffer.str ();
194+ EXPECT_TRUE (error_output.find (" [WARN] Image loading failed:" ) != std::string::npos);
195+
196+ cerr_buffer.str (" " );
197+ cerr_buffer.clear ();
198+
199+ Logger::logSDLTTFError (LogLevel::ERROR, " Font loading failed" );
200+ error_output = cerr_buffer.str ();
201+ EXPECT_TRUE (error_output.find (" [ERROR] Font loading failed:" ) != std::string::npos);
202+
203+ cerr_buffer.str (" " );
204+ cerr_buffer.clear ();
205+
206+ Logger::logSDLMixerError (LogLevel::ERROR, " Audio initialization failed" );
207+ error_output = cerr_buffer.str ();
208+ EXPECT_TRUE (error_output.find (" [ERROR] Audio initialization failed:" ) != std::string::npos);
209+ }
210+
211+ // Test that log calls are thread-safe (basic test)
212+ TEST_F (LoggerTest, BasicThreadSafety) {
213+ // Simple test that multiple calls don't interfere
214+ for (int i = 0 ; i < 10 ; ++i) {
215+ Logger::info (" Message " + std::to_string (i));
216+ }
217+
218+ std::string output = cout_buffer.str ();
219+
220+ // Check that all messages appear
221+ for (int i = 0 ; i < 10 ; ++i) {
222+ EXPECT_TRUE (output.find (" Message " + std::to_string (i)) != std::string::npos);
223+ }
224+ }
0 commit comments