Some checks are pending
Run unit tests / run-unit-tests (push) Waiting to run
Add logging and tests for the homepage and settings page. Make both support dependency injection. Reviewed-on: https://gitea.subcultureofone.org/greg/tkr/pulls/42 Co-authored-by: Greg Sarjeant <greg@subcultureofone.org> Co-committed-by: Greg Sarjeant <greg@subcultureofone.org>
367 lines
13 KiB
PHP
367 lines
13 KiB
PHP
<?php
|
|
require_once dirname(dirname(dirname(__DIR__))) . "/config/bootstrap.php";
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
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');
|
|
|
|
// Set up global config for logging level (DEBUG = 1)
|
|
global $config;
|
|
$config = new stdClass();
|
|
$config->logLevel = 1; // Allow DEBUG level logs
|
|
|
|
// Create mock PDO (needed for base constructor)
|
|
$this->mockPdo = $this->createMock(PDO::class);
|
|
|
|
// Create real config and user objects with mocked PDO
|
|
$this->config = new ConfigModel($this->mockPdo);
|
|
$this->config->siteTitle = 'Test Site';
|
|
$this->config->siteDescription = 'Test Description';
|
|
$this->config->baseUrl = 'https://example.com';
|
|
$this->config->basePath = '/tkr';
|
|
$this->config->itemsPerPage = 10;
|
|
|
|
$this->user = new UserModel($this->mockPdo);
|
|
$this->user->username = 'testuser';
|
|
$this->user->displayName = 'Test User';
|
|
$this->user->website = 'https://example.com';
|
|
}
|
|
|
|
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
|
|
{
|
|
$controller = new AdminController($this->mockPdo, $this->config, $this->user);
|
|
$data = $controller->getAdminData(false);
|
|
|
|
// Should return proper structure
|
|
$this->assertArrayHasKey('config', $data);
|
|
$this->assertArrayHasKey('user', $data);
|
|
$this->assertArrayHasKey('isSetup', $data);
|
|
|
|
// Should be the injected instances
|
|
$this->assertSame($this->config, $data['config']);
|
|
$this->assertSame($this->user, $data['user']);
|
|
$this->assertFalse($data['isSetup']);
|
|
}
|
|
|
|
public function testGetAdminDataSetupMode(): void
|
|
{
|
|
$controller = new AdminController($this->mockPdo, $this->config, $this->user);
|
|
$data = $controller->getAdminData(true);
|
|
|
|
// Should return proper structure
|
|
$this->assertArrayHasKey('config', $data);
|
|
$this->assertArrayHasKey('user', $data);
|
|
$this->assertArrayHasKey('isSetup', $data);
|
|
|
|
// Should be the injected instances
|
|
$this->assertSame($this->config, $data['config']);
|
|
$this->assertSame($this->user, $data['user']);
|
|
$this->assertTrue($data['isSetup']);
|
|
}
|
|
|
|
public function testProcessSettingsSaveWithEmptyData(): void
|
|
{
|
|
$controller = new AdminController($this->mockPdo, $this->config, $this->user);
|
|
$result = $controller->processSettingsSave([], false);
|
|
|
|
$this->assertFalse($result['success']);
|
|
$this->assertContains('No data provided', $result['errors']);
|
|
}
|
|
|
|
public function testProcessSettingsSaveValidationErrors(): void
|
|
{
|
|
$controller = new AdminController($this->mockPdo, $this->config, $this->user);
|
|
|
|
// Test data with multiple validation errors
|
|
$postData = [
|
|
'username' => '', // Missing username
|
|
'display_name' => '', // Missing display name
|
|
'website' => 'invalid-url', // Invalid URL
|
|
'site_title' => '', // Missing site title
|
|
'base_url' => '', // Missing base URL
|
|
'base_path' => 'invalid', // Invalid base path
|
|
'items_per_page' => 100, // Too high
|
|
'password' => 'test123',
|
|
'confirm_password' => 'different' // Passwords don't match
|
|
];
|
|
|
|
$result = $controller->processSettingsSave($postData, false);
|
|
|
|
$this->assertFalse($result['success']);
|
|
$this->assertNotEmpty($result['errors']);
|
|
|
|
// Should have multiple validation errors
|
|
$this->assertGreaterThan(5, count($result['errors']));
|
|
}
|
|
|
|
public function testProcessSettingsSaveValidData(): void
|
|
{
|
|
// Mock PDO to simulate successful database operations
|
|
$mockStatement = $this->createMock(PDOStatement::class);
|
|
$mockStatement->method('execute')->willReturn(true);
|
|
$mockStatement->method('fetchColumn')->willReturn(1); // Existing record count
|
|
$mockStatement->method('fetch')->willReturnOnConsecutiveCalls(
|
|
[
|
|
'site_title' => 'Updated Site',
|
|
'site_description' => 'Updated Description',
|
|
'base_url' => 'https://updated.com',
|
|
'base_path' => '/updated',
|
|
'items_per_page' => 15,
|
|
'css_id' => null,
|
|
'strict_accessibility' => true,
|
|
'log_level' => 2
|
|
],
|
|
[
|
|
'username' => 'newuser',
|
|
'display_name' => 'New User',
|
|
'website' => 'https://example.com',
|
|
'mood' => ''
|
|
]
|
|
);
|
|
|
|
$this->mockPdo->method('prepare')->willReturn($mockStatement);
|
|
$this->mockPdo->method('query')->willReturn($mockStatement);
|
|
|
|
// Create models with mocked PDO
|
|
$config = new ConfigModel($this->mockPdo);
|
|
$user = new UserModel($this->mockPdo);
|
|
|
|
$controller = new AdminController($this->mockPdo, $config, $user);
|
|
|
|
$postData = [
|
|
'username' => 'newuser',
|
|
'display_name' => 'New User',
|
|
'website' => 'https://example.com',
|
|
'site_title' => 'Updated Site',
|
|
'site_description' => 'Updated Description',
|
|
'base_url' => 'https://updated.com',
|
|
'base_path' => '/updated',
|
|
'items_per_page' => 15,
|
|
'strict_accessibility' => 'on',
|
|
'log_level' => 2
|
|
];
|
|
|
|
$result = $controller->processSettingsSave($postData, false);
|
|
|
|
$this->assertTrue($result['success']);
|
|
$this->assertEmpty($result['errors']);
|
|
}
|
|
|
|
public function testProcessSettingsSaveWithPassword(): void
|
|
{
|
|
// Mock PDO for successful save 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' => ''
|
|
]
|
|
);
|
|
|
|
// Verify password hash is called
|
|
$this->mockPdo->expects($this->atLeastOnce())
|
|
->method('prepare')
|
|
->willReturn($mockStatement);
|
|
|
|
$this->mockPdo->method('query')->willReturn($mockStatement);
|
|
|
|
// Create models with mocked PDO
|
|
$config = new ConfigModel($this->mockPdo);
|
|
$user = new UserModel($this->mockPdo);
|
|
|
|
$controller = new AdminController($this->mockPdo, $config, $user);
|
|
|
|
$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,
|
|
'password' => 'newpassword',
|
|
'confirm_password' => 'newpassword'
|
|
];
|
|
|
|
$result = $controller->processSettingsSave($postData, false);
|
|
|
|
$this->assertTrue($result['success']);
|
|
}
|
|
|
|
public function testProcessSettingsSaveDatabaseError(): void
|
|
{
|
|
// Mock PDO to throw exception on save
|
|
$this->mockPdo->method('query')
|
|
->willThrowException(new PDOException("Database error"));
|
|
|
|
$config = new ConfigModel($this->mockPdo);
|
|
$user = new UserModel($this->mockPdo);
|
|
|
|
$controller = new AdminController($this->mockPdo, $config, $user);
|
|
|
|
$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
|
|
];
|
|
|
|
$result = $controller->processSettingsSave($postData, false);
|
|
|
|
$this->assertFalse($result['success']);
|
|
$this->assertContains('Failed to save settings', $result['errors']);
|
|
}
|
|
|
|
public function testLoggingOnAdminPageLoad(): void
|
|
{
|
|
$controller = new AdminController($this->mockPdo, $this->config, $this->user);
|
|
$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($this->mockPdo, $this->config, $this->user);
|
|
$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($this->mockPdo, $this->config, $this->user);
|
|
|
|
$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->processSettingsSave($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);
|
|
|
|
$controller = new AdminController($this->mockPdo, $config, $user);
|
|
|
|
$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->processSettingsSave($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);
|
|
}
|
|
} |