Focus unit tests on business logic and fix log test state pollution (#53)
Reviewed-on: https://gitea.subcultureofone.org/greg/tkr/pulls/53 Co-authored-by: Greg Sarjeant <greg@subcultureofone.org> Co-committed-by: Greg Sarjeant <greg@subcultureofone.org>
This commit is contained in:
		
							parent
							
								
									832b7b95fa
								
							
						
					
					
						commit
						7816581216
					
				| @ -7,15 +7,9 @@ class AdminControllerTest extends TestCase | ||||
|     private PDO $mockPdo; | ||||
|     private ConfigModel $config; | ||||
|     private UserModel $user; | ||||
|     private string $tempLogDir; | ||||
| 
 | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         // Set up temporary logging
 | ||||
|         $this->tempLogDir = sys_get_temp_dir() . '/tkr_test_logs_' . uniqid(); | ||||
|         mkdir($this->tempLogDir . '/logs', 0777, true); | ||||
|         Log::init($this->tempLogDir . '/logs/tkr.log'); | ||||
| 
 | ||||
|         // Create mock PDO
 | ||||
|         $this->mockPdo = $this->createMock(PDO::class); | ||||
|          | ||||
| @ -39,29 +33,6 @@ class AdminControllerTest extends TestCase | ||||
|             'config' => $this->config, | ||||
|             'user' => $this->user, | ||||
|         ]; | ||||
|          | ||||
|         // Set log level on config for Log class
 | ||||
|         $this->config->logLevel = 1; // Allow DEBUG level logs
 | ||||
|     } | ||||
| 
 | ||||
|     protected function tearDown(): void | ||||
|     { | ||||
|         // Clean up temp directory
 | ||||
|         if (is_dir($this->tempLogDir)) { | ||||
|             $this->deleteDirectory($this->tempLogDir); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private function deleteDirectory(string $dir): void | ||||
|     { | ||||
|         if (!is_dir($dir)) return; | ||||
|          | ||||
|         $files = array_diff(scandir($dir), ['.', '..']); | ||||
|         foreach ($files as $file) { | ||||
|             $path = $dir . '/' . $file; | ||||
|             is_dir($path) ? $this->deleteDirectory($path) : unlink($path); | ||||
|         } | ||||
|         rmdir($dir); | ||||
|     } | ||||
| 
 | ||||
|     public function testGetAdminDataRegularMode(): void | ||||
| @ -281,113 +252,4 @@ class AdminControllerTest extends TestCase | ||||
|         $this->assertContains('Failed to save settings', $result['errors']); | ||||
|     } | ||||
| 
 | ||||
|     public function testLoggingOnAdminPageLoad(): void | ||||
|     { | ||||
|         $controller = new AdminController(); | ||||
|         $controller->getAdminData(false); | ||||
|          | ||||
|         // Check that logs were written
 | ||||
|         $logFile = $this->tempLogDir . '/logs/tkr.log'; | ||||
|         $this->assertFileExists($logFile); | ||||
|          | ||||
|         $logContent = file_get_contents($logFile); | ||||
|         $this->assertStringContainsString('Loading admin page', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testLoggingOnSetupPageLoad(): void | ||||
|     { | ||||
|         $controller = new AdminController(); | ||||
|         $controller->getAdminData(true); | ||||
|          | ||||
|         // Check that logs were written
 | ||||
|         $logFile = $this->tempLogDir . '/logs/tkr.log'; | ||||
|         $this->assertFileExists($logFile); | ||||
|          | ||||
|         $logContent = file_get_contents($logFile); | ||||
|         $this->assertStringContainsString('Loading admin page (setup mode)', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testLoggingOnValidationErrors(): void | ||||
|     { | ||||
|         $controller = new AdminController(); | ||||
|          | ||||
|         $postData = [ | ||||
|             'username' => '',  // Will cause validation error
 | ||||
|             'display_name' => 'Test User', | ||||
|             'site_title' => 'Test Site', | ||||
|             'base_url' => 'https://example.com', | ||||
|             'base_path' => '/tkr', | ||||
|             'items_per_page' => 10 | ||||
|         ]; | ||||
|          | ||||
|         $controller->saveSettings($postData, false); | ||||
|          | ||||
|         // Check that logs were written
 | ||||
|         $logFile = $this->tempLogDir . '/logs/tkr.log'; | ||||
|         $this->assertFileExists($logFile); | ||||
|          | ||||
|         $logContent = file_get_contents($logFile); | ||||
|         $this->assertStringContainsString('Settings validation failed', $logContent); | ||||
|         $this->assertStringContainsString('Validation error: Username is required', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testLoggingOnSuccessfulSave(): void | ||||
|     { | ||||
|         // Mock successful database operations
 | ||||
|         $mockStatement = $this->createMock(PDOStatement::class); | ||||
|         $mockStatement->method('execute')->willReturn(true); | ||||
|         $mockStatement->method('fetchColumn')->willReturn(1); | ||||
|         $mockStatement->method('fetch')->willReturnOnConsecutiveCalls( | ||||
|             [ | ||||
|                 'site_title' => 'Test Site', | ||||
|                 'site_description' => 'Test Description', | ||||
|                 'base_url' => 'https://example.com', | ||||
|                 'base_path' => '/tkr', | ||||
|                 'items_per_page' => 10, | ||||
|                 'css_id' => null, | ||||
|                 'strict_accessibility' => true, | ||||
|                 'log_level' => 2 | ||||
|             ], | ||||
|             [ | ||||
|                 'username' => 'testuser', | ||||
|                 'display_name' => 'Test User', | ||||
|                 'website' => '', | ||||
|                 'mood' => '' | ||||
|             ] | ||||
|         ); | ||||
| 
 | ||||
|         $this->mockPdo->method('prepare')->willReturn($mockStatement); | ||||
|         $this->mockPdo->method('query')->willReturn($mockStatement); | ||||
| 
 | ||||
|         $config = new ConfigModel($this->mockPdo); | ||||
|         $user = new UserModel($this->mockPdo); | ||||
|          | ||||
|         // Update global $app with test models
 | ||||
|         global $app; | ||||
|         $app['config'] = $config; | ||||
|         $app['user'] = $user; | ||||
|          | ||||
|         $controller = new AdminController(); | ||||
|          | ||||
|         $postData = [ | ||||
|             'username' => 'testuser', | ||||
|             'display_name' => 'Test User', | ||||
|             'site_title' => 'Test Site', | ||||
|             'site_description' => 'Test Description', | ||||
|             'base_url' => 'https://example.com', | ||||
|             'base_path' => '/tkr', | ||||
|             'items_per_page' => 10 | ||||
|         ]; | ||||
|          | ||||
|         $controller->saveSettings($postData, false); | ||||
|          | ||||
|         // Check that logs were written
 | ||||
|         $logFile = $this->tempLogDir . '/logs/tkr.log'; | ||||
|         $this->assertFileExists($logFile); | ||||
|          | ||||
|         $logContent = file_get_contents($logFile); | ||||
|         $this->assertStringContainsString('Processing settings for user: testuser', $logContent); | ||||
|         $this->assertStringContainsString('Site settings updated', $logContent); | ||||
|         $this->assertStringContainsString('User profile updated', $logContent); | ||||
|     } | ||||
| } | ||||
| @ -7,14 +7,11 @@ class HomeControllerTest extends TestCase | ||||
|     private PDOStatement $mockStatement; | ||||
|     private ConfigModel $mockConfig; | ||||
|     private UserModel $mockUser; | ||||
|     private string $tempLogDir; | ||||
| 
 | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         // Set up temporary logging
 | ||||
|         $this->tempLogDir = sys_get_temp_dir() . '/tkr_test_logs_' . uniqid(); | ||||
|         mkdir($this->tempLogDir . '/logs', 0777, true); | ||||
|         Log::init($this->tempLogDir . '/logs/tkr.log'); | ||||
|         // Reset Log state to prevent test pollution
 | ||||
|         Log::init(sys_get_temp_dir() . '/tkr_controller_test.log'); | ||||
|          | ||||
|         // Create mock PDO and PDOStatement
 | ||||
|         $this->mockStatement = $this->createMock(PDOStatement::class); | ||||
| @ -37,29 +34,6 @@ class HomeControllerTest extends TestCase | ||||
|             'config' => $this->mockConfig, | ||||
|             'user' => $this->mockUser, | ||||
|         ]; | ||||
|          | ||||
|         // Set log level on config for Log class
 | ||||
|         $this->mockConfig->logLevel = 1; // Allow DEBUG level logs
 | ||||
|     } | ||||
| 
 | ||||
|     protected function tearDown(): void | ||||
|     { | ||||
|         // Clean up temp directory
 | ||||
|         if (is_dir($this->tempLogDir)) { | ||||
|             $this->deleteDirectory($this->tempLogDir); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private function deleteDirectory(string $dir): void | ||||
|     { | ||||
|         if (!is_dir($dir)) return; | ||||
|          | ||||
|         $files = array_diff(scandir($dir), ['.', '..']); | ||||
|         foreach ($files as $file) { | ||||
|             $path = $dir . '/' . $file; | ||||
|             is_dir($path) ? $this->deleteDirectory($path) : unlink($path); | ||||
|         } | ||||
|         rmdir($dir); | ||||
|     } | ||||
| 
 | ||||
|     private function setupMockDatabase(array $tickData): void | ||||
| @ -246,73 +220,4 @@ class HomeControllerTest extends TestCase | ||||
|         $this->assertEquals('Failed to save tick', $result['message']); | ||||
|     } | ||||
| 
 | ||||
|     public function testLoggingOnHomePageLoad(): void | ||||
|     { | ||||
|         $testTicks = [ | ||||
|             ['id' => 1, 'timestamp' => '2025-01-31 12:00:00', 'tick' => 'Test tick'] | ||||
|         ]; | ||||
|         $this->setupMockDatabase($testTicks); | ||||
|          | ||||
|         $controller = new HomeController(); | ||||
|         $controller->getHomeData(1); | ||||
|          | ||||
|         // Check that logs were written
 | ||||
|         $logFile = $this->tempLogDir . '/logs/tkr.log'; | ||||
|         $this->assertFileExists($logFile); | ||||
|          | ||||
|         $logContent = file_get_contents($logFile); | ||||
|         $this->assertStringContainsString('Loading home page 1', $logContent); | ||||
|         $this->assertStringContainsString('Home page loaded with 1 ticks', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testLoggingOnTickCreation(): void | ||||
|     { | ||||
|         $this->setupMockDatabaseForInsert(true); | ||||
|          | ||||
|         $controller = new HomeController(); | ||||
|         $postData = ['new_tick' => 'Test tick for logging']; | ||||
|          | ||||
|         $controller->processTick($postData); | ||||
|          | ||||
|         // Check that logs were written
 | ||||
|         $logFile = $this->tempLogDir . '/logs/tkr.log'; | ||||
|         $this->assertFileExists($logFile); | ||||
|          | ||||
|         $logContent = file_get_contents($logFile); | ||||
|         $this->assertStringContainsString('New tick created: Test tick for logging', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testLoggingOnEmptyTick(): void | ||||
|     { | ||||
|         $controller = new HomeController(); | ||||
|         $postData = ['new_tick' => '']; | ||||
|          | ||||
|         $controller->processTick($postData); | ||||
|          | ||||
|         // Check that logs were written
 | ||||
|         $logFile = $this->tempLogDir . '/logs/tkr.log'; | ||||
|          | ||||
|         // The log file should exist (Log::init creates it) and contain the debug message
 | ||||
|         $this->assertFileExists($logFile); | ||||
|          | ||||
|         $logContent = file_get_contents($logFile); | ||||
|         $this->assertStringContainsString('Empty tick submission ignored', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testLoggingOnDatabaseError(): void | ||||
|     { | ||||
|         $this->setupMockDatabaseForInsert(false); | ||||
|          | ||||
|         $controller = new HomeController(); | ||||
|         $postData = ['new_tick' => 'This will fail']; | ||||
|          | ||||
|         $controller->processTick($postData); | ||||
|          | ||||
|         // Check that logs were written
 | ||||
|         $logFile = $this->tempLogDir . '/logs/tkr.log'; | ||||
|         $this->assertFileExists($logFile); | ||||
|          | ||||
|         $logContent = file_get_contents($logFile); | ||||
|         $this->assertStringContainsString('Failed to save tick: Database error', $logContent); | ||||
|     } | ||||
| } | ||||
| @ -6,19 +6,12 @@ class TickControllerTest extends TestCase | ||||
|     private $mockPdo; | ||||
|     private $config; | ||||
|     private $user; | ||||
|     private string $tempLogDir; | ||||
|     private string $testLogFile; | ||||
| 
 | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         // Set up log capture
 | ||||
|         $this->tempLogDir = sys_get_temp_dir() . '/tkr_test_logs_' . uniqid(); | ||||
|         mkdir($this->tempLogDir, 0777, true); | ||||
|         // Reset Log state to prevent test pollution
 | ||||
|         Log::init(sys_get_temp_dir() . '/tkr_controller_test.log'); | ||||
|          | ||||
|         $this->testLogFile = $this->tempLogDir . '/tkr.log'; | ||||
|         Log::init($this->testLogFile); | ||||
|         Log::setRouteContext('GET tick/123'); | ||||
| 
 | ||||
|         // Set up mocks
 | ||||
|         $this->mockPdo = $this->createMock(PDO::class); | ||||
|          | ||||
| @ -26,7 +19,6 @@ class TickControllerTest extends TestCase | ||||
|         $this->config->baseUrl = 'https://example.com'; | ||||
|         $this->config->basePath = '/tkr/'; | ||||
|         $this->config->itemsPerPage = 10; | ||||
|         $this->config->logLevel = 1; // DEBUG level for testing
 | ||||
|          | ||||
|         $this->user = new UserModel($this->mockPdo); | ||||
| 
 | ||||
| @ -39,25 +31,6 @@ class TickControllerTest extends TestCase | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     protected function tearDown(): void | ||||
|     { | ||||
|         if (is_dir($this->tempLogDir)) { | ||||
|             $this->deleteDirectory($this->tempLogDir); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private function deleteDirectory(string $dir): void | ||||
|     { | ||||
|         if (!is_dir($dir)) return; | ||||
|          | ||||
|         $files = array_diff(scandir($dir), ['.', '..']); | ||||
|         foreach ($files as $file) { | ||||
|             $path = $dir . '/' . $file; | ||||
|             is_dir($path) ? $this->deleteDirectory($path) : unlink($path); | ||||
|         } | ||||
|         rmdir($dir); | ||||
|     } | ||||
| 
 | ||||
|     public function testIndexWithValidTick(): void | ||||
|     { | ||||
|         // Set up mock database response for successful tick retrieval
 | ||||
| @ -98,11 +71,6 @@ class TickControllerTest extends TestCase | ||||
|         // Should contain the tick content (through the template)
 | ||||
|         // Note: We can't easily test the full template rendering without more setup,
 | ||||
|         // but we can verify no error occurred
 | ||||
| 
 | ||||
|         // Verify logging
 | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString('Fetching tick with ID: 123', $logContent); | ||||
|         $this->assertStringContainsString('Successfully loaded tick 123: This is a test tick with some content', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testIndexWithNonexistentTick(): void | ||||
| @ -132,11 +100,6 @@ class TickControllerTest extends TestCase | ||||
| 
 | ||||
|         // Should return 404 error
 | ||||
|         $this->assertStringContainsString('404 - Tick Not Found', $output); | ||||
| 
 | ||||
|         // Verify logging
 | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString('Fetching tick with ID: 999', $logContent); | ||||
|         $this->assertStringContainsString('Tick not found for ID: 999', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testIndexWithEmptyTickData(): void | ||||
| @ -166,10 +129,6 @@ class TickControllerTest extends TestCase | ||||
| 
 | ||||
|         // Should return 404 error for empty data
 | ||||
|         $this->assertStringContainsString('404 - Tick Not Found', $output); | ||||
| 
 | ||||
|         // Verify logging
 | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString('Tick not found for ID: 456', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testIndexWithDatabaseException(): void | ||||
| @ -190,84 +149,6 @@ class TickControllerTest extends TestCase | ||||
| 
 | ||||
|         // Should return 500 error
 | ||||
|         $this->assertStringContainsString('500 - Internal Server Error', $output); | ||||
| 
 | ||||
|         // Verify error logging
 | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString('Failed to load tick 123: Database connection failed', $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testIndexWithLongTickContent(): void | ||||
|     { | ||||
|         // Test logging truncation for long tick content
 | ||||
|         $longContent = str_repeat('This is a very long tick content that should be truncated in the logs. ', 10); | ||||
|          | ||||
|         $mockStatement = $this->createMock(PDOStatement::class); | ||||
|         $mockStatement->expects($this->once()) | ||||
|                       ->method('execute') | ||||
|                       ->with([789]); | ||||
|         $mockStatement->expects($this->once()) | ||||
|                       ->method('fetch') | ||||
|                       ->with(PDO::FETCH_ASSOC) | ||||
|                       ->willReturn([ | ||||
|                           'timestamp' => '2025-01-31 15:30:00', | ||||
|                           'tick' => $longContent | ||||
|                       ]); | ||||
| 
 | ||||
|         $this->mockPdo->expects($this->once()) | ||||
|                       ->method('prepare') | ||||
|                       ->with('SELECT timestamp, tick FROM tick WHERE id=?') | ||||
|                       ->willReturn($mockStatement); | ||||
| 
 | ||||
|         // Capture output
 | ||||
|         ob_start(); | ||||
|          | ||||
|         $controller = new TickController(); | ||||
|         $controller->index(789); | ||||
|          | ||||
|         $output = ob_get_clean(); | ||||
| 
 | ||||
|         // Verify logging shows truncated content with ellipsis
 | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString('Successfully loaded tick 789:', $logContent); | ||||
|         $this->assertStringContainsString('...', $logContent); // Should be truncated
 | ||||
|          | ||||
|         // Verify the log doesn't contain the full long content
 | ||||
|         $this->assertStringNotContainsString($longContent, $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testIndexWithShortTickContent(): void | ||||
|     { | ||||
|         // Test that short content is not truncated in logs
 | ||||
|         $shortContent = 'Short tick'; | ||||
|          | ||||
|         $mockStatement = $this->createMock(PDOStatement::class); | ||||
|         $mockStatement->expects($this->once()) | ||||
|                       ->method('execute') | ||||
|                       ->with([100]); | ||||
|         $mockStatement->expects($this->once()) | ||||
|                       ->method('fetch') | ||||
|                       ->with(PDO::FETCH_ASSOC) | ||||
|                       ->willReturn([ | ||||
|                           'timestamp' => '2025-01-31 09:15:00', | ||||
|                           'tick' => $shortContent | ||||
|                       ]); | ||||
| 
 | ||||
|         $this->mockPdo->expects($this->once()) | ||||
|                       ->method('prepare') | ||||
|                       ->with('SELECT timestamp, tick FROM tick WHERE id=?') | ||||
|                       ->willReturn($mockStatement); | ||||
| 
 | ||||
|         // Capture output
 | ||||
|         ob_start(); | ||||
|          | ||||
|         $controller = new TickController(); | ||||
|         $controller->index(100); | ||||
|          | ||||
|         $output = ob_get_clean(); | ||||
| 
 | ||||
|         // Verify logging shows full content without ellipsis
 | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString('Successfully loaded tick 100: Short tick', $logContent); | ||||
|         $this->assertStringNotContainsString('...', $logContent); // Should NOT be truncated
 | ||||
|     } | ||||
| } | ||||
| @ -31,28 +31,44 @@ class LogTest extends TestCase | ||||
|     { | ||||
|         if (!is_dir($dir)) return; | ||||
|          | ||||
|         $files = array_diff(scandir($dir), ['.', '..']); | ||||
|         foreach ($files as $file) { | ||||
|             $path = $dir . '/' . $file; | ||||
|             is_dir($path) ? $this->deleteDirectory($path) : unlink($path); | ||||
|         $iterator = new RecursiveIteratorIterator( | ||||
|             new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), | ||||
|             RecursiveIteratorIterator::CHILD_FIRST | ||||
|         ); | ||||
|          | ||||
|         foreach ($iterator as $path) { | ||||
|             $path->isDir() ? rmdir($path->getRealPath()) : unlink($path->getRealPath()); | ||||
|         } | ||||
|         rmdir($dir); | ||||
|     } | ||||
|      | ||||
|     private function setLogLevel(int $level): void | ||||
|     { | ||||
|         global $app; | ||||
|         $app = ['config' => (object)['logLevel' => $level]]; | ||||
|     } | ||||
|      | ||||
|     private function assertLogContains(string $message): void | ||||
|     { | ||||
|         $this->assertFileExists($this->testLogFile); | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString($message, $logContent); | ||||
|     } | ||||
|      | ||||
|     private function assertLogDoesNotContain(string $message): void | ||||
|     { | ||||
|         $this->assertFileExists($this->testLogFile); | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringNotContainsString($message, $logContent); | ||||
|     } | ||||
| 
 | ||||
|     public function testSetRouteContext(): void | ||||
|     { | ||||
|         Log::setRouteContext('GET /admin'); | ||||
|          | ||||
|         // Create a mock app config for log level
 | ||||
|         global $app; | ||||
|         $app = [ | ||||
|             'config' => (object)['logLevel' => 1] // DEBUG level
 | ||||
|         ]; | ||||
|         $this->setLogLevel(1); // DEBUG level
 | ||||
|          | ||||
|         Log::debug('Test message'); | ||||
|          | ||||
|         $this->assertFileExists($this->testLogFile); | ||||
|          | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString('[GET /admin]', $logContent); | ||||
|         $this->assertStringContainsString('Test message', $logContent); | ||||
| @ -61,11 +77,7 @@ class LogTest extends TestCase | ||||
|     public function testEmptyRouteContext(): void | ||||
|     { | ||||
|         Log::setRouteContext(''); | ||||
|          | ||||
|         global $app; | ||||
|         $app = [ | ||||
|             'config' => (object)['logLevel' => 1] | ||||
|         ]; | ||||
|         $this->setLogLevel(1); | ||||
|          | ||||
|         Log::info('Test without route'); | ||||
|          | ||||
| @ -80,32 +92,23 @@ class LogTest extends TestCase | ||||
| 
 | ||||
|     public function testLogLevelFiltering(): void | ||||
|     { | ||||
|         global $app; | ||||
|         $app = [ | ||||
|             'config' => (object)['logLevel' => 3] // WARNING level
 | ||||
|         ]; | ||||
|         $this->setLogLevel(3); // WARNING level
 | ||||
|          | ||||
|         Log::debug('Debug message');   // Should be filtered out
 | ||||
|         Log::info('Info message');     // Should be filtered out  
 | ||||
|         Log::warning('Warning message'); // Should be logged
 | ||||
|         Log::error('Error message');   // Should be logged
 | ||||
|          | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|          | ||||
|         $this->assertStringNotContainsString('Debug message', $logContent); | ||||
|         $this->assertStringNotContainsString('Info message', $logContent); | ||||
|         $this->assertStringContainsString('Warning message', $logContent); | ||||
|         $this->assertStringContainsString('Error message', $logContent); | ||||
|         $this->assertLogDoesNotContain('Debug message'); | ||||
|         $this->assertLogDoesNotContain('Info message'); | ||||
|         $this->assertLogContains('Warning message'); | ||||
|         $this->assertLogContains('Error message'); | ||||
|     } | ||||
| 
 | ||||
|     public function testLogMessageFormat(): void | ||||
|     { | ||||
|         Log::setRouteContext('POST /admin'); | ||||
|          | ||||
|         global $app; | ||||
|         $app = [ | ||||
|             'config' => (object)['logLevel' => 1] | ||||
|         ]; | ||||
|         $this->setLogLevel(1); | ||||
|          | ||||
|         Log::error('Test error message'); | ||||
|          | ||||
| @ -129,14 +132,16 @@ class LogTest extends TestCase | ||||
|          | ||||
|         // init() should create the directory
 | ||||
|         $this->assertDirectoryExists(dirname($newLogFile)); | ||||
|          | ||||
|         // Verify we can actually write to it
 | ||||
|         $this->setLogLevel(1); | ||||
|         Log::info('Test directory creation'); | ||||
|         $this->assertFileExists($newLogFile); | ||||
|     } | ||||
| 
 | ||||
|     public function testLogRotation(): void | ||||
|     { | ||||
|         global $app; | ||||
|         $app = [ | ||||
|             'config' => (object)['logLevel' => 1] | ||||
|         ]; | ||||
|         $this->setLogLevel(1); | ||||
|          | ||||
|         // Create a log file with exactly 1000 lines (the rotation threshold)
 | ||||
|         $logLines = str_repeat("[2025-01-31 12:00:00] INFO: 127.0.0.1 - Test line\n", 1000); | ||||
| @ -145,32 +150,49 @@ class LogTest extends TestCase | ||||
|         // This should trigger rotation
 | ||||
|         Log::info('This should trigger rotation'); | ||||
|          | ||||
|         // Original log should be rotated to .1
 | ||||
|         // Verify rotation happened
 | ||||
|         $this->assertFileExists($this->testLogFile . '.1'); | ||||
|         $this->assertLogContains('This should trigger rotation'); | ||||
|     } | ||||
|      | ||||
|     public function testLogRotationLimitsFileCount(): void | ||||
|     { | ||||
|         $this->setLogLevel(1); | ||||
|          | ||||
|         // New log should contain the new message
 | ||||
|         $newLogContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringContainsString('This should trigger rotation', $newLogContent); | ||||
|         // Create 5 existing rotated log files (.1 through .5)
 | ||||
|         for ($i = 1; $i <= 5; $i++) { | ||||
|             file_put_contents($this->testLogFile . '.' . $i, "Old log file $i\n"); | ||||
|         } | ||||
|          | ||||
|         // Rotated log should contain old content
 | ||||
|         $rotatedContent = file_get_contents($this->testLogFile . '.1'); | ||||
|         $this->assertStringContainsString('Test line', $rotatedContent); | ||||
|         // Create main log file at rotation threshold
 | ||||
|         $logLines = str_repeat("[2025-01-31 12:00:00] INFO: 127.0.0.1 - Test line\n", 1000); | ||||
|         file_put_contents($this->testLogFile, $logLines); | ||||
|          | ||||
|         // This should trigger rotation and delete the oldest file (.5)
 | ||||
|         Log::info('Trigger rotation with max files'); | ||||
|          | ||||
|         // Verify rotation happened and file count is limited
 | ||||
|         $this->assertFileExists($this->testLogFile . '.1'); // New rotated file
 | ||||
|         $this->assertFileExists($this->testLogFile . '.2'); // Old .1 became .2
 | ||||
|         $this->assertFileExists($this->testLogFile . '.3'); // Old .2 became .3
 | ||||
|         $this->assertFileExists($this->testLogFile . '.4'); // Old .3 became .4
 | ||||
|         $this->assertFileExists($this->testLogFile . '.5'); // Old .4 became .5
 | ||||
|         $this->assertFileDoesNotExist($this->testLogFile . '.6'); // Old .5 was deleted
 | ||||
|          | ||||
|         $this->assertLogContains('Trigger rotation with max files'); | ||||
|     } | ||||
| 
 | ||||
|     public function testDefaultLogLevelWhenConfigMissing(): void | ||||
|     { | ||||
|         // Set up config without logLevel property (simulates missing config value)
 | ||||
|         global $app; | ||||
|         $app = [ | ||||
|             'config' => (object)[] // Empty config object, no logLevel property
 | ||||
|         ]; | ||||
|         $app = ['config' => (object)[]]; | ||||
|          | ||||
|         // Should not throw errors and should default to INFO level
 | ||||
|         Log::debug('Debug message');  // Should be filtered out (default INFO level = 2)
 | ||||
|         Log::info('Info message');    // Should be logged
 | ||||
|          | ||||
|         $logContent = file_get_contents($this->testLogFile); | ||||
|         $this->assertStringNotContainsString('Debug message', $logContent); | ||||
|         $this->assertStringContainsString('Info message', $logContent); | ||||
|         $this->assertLogDoesNotContain('Debug message'); | ||||
|         $this->assertLogContains('Info message'); | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user