Add comprehensive unit tests for Security, UserModel, and Validation utilities
- Implemented SecurityTest to validate token generation, CSRF protection, input sanitization, and rate limiting. - Created UserModelTest to ensure correct database operations for user management, including creation, updating, banning, and fetching active users. - Developed ValidationTest to verify input validation and sanitization for user IDs, nicknames, messages, and API requests. - Introduced Security and Validation utility classes with methods for secure token generation, input sanitization, and comprehensive validation rules.
This commit is contained in:
parent
5692874b10
commit
41cd7a4fd8
32 changed files with 5796 additions and 368 deletions
187
tests/unit/SecurityTest.php
Normal file
187
tests/unit/SecurityTest.php
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test Security utility functions
|
||||
*/
|
||||
class SecurityTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
// Clear any previous session data
|
||||
$_SESSION = [];
|
||||
$_POST = [];
|
||||
$_GET = [];
|
||||
}
|
||||
|
||||
public function testGenerateSecureToken()
|
||||
{
|
||||
$token1 = Security::generateSecureToken(16);
|
||||
$token2 = Security::generateSecureToken(16);
|
||||
|
||||
// Test length
|
||||
$this->assertEquals(32, strlen($token1)); // 16 bytes = 32 hex chars
|
||||
$this->assertEquals(32, strlen($token2));
|
||||
|
||||
// Test uniqueness
|
||||
$this->assertNotEquals($token1, $token2);
|
||||
|
||||
// Test valid hex characters
|
||||
$this->assertMatchesRegularExpression('/^[a-f0-9]+$/', $token1);
|
||||
$this->assertMatchesRegularExpression('/^[a-f0-9]+$/', $token2);
|
||||
}
|
||||
|
||||
public function testGenerateSecureUserId()
|
||||
{
|
||||
$userId1 = Security::generateSecureUserId();
|
||||
$userId2 = Security::generateSecureUserId();
|
||||
|
||||
// Test format (32 char hex)
|
||||
$this->assertEquals(32, strlen($userId1));
|
||||
$this->assertEquals(32, strlen($userId2));
|
||||
|
||||
// Test uniqueness
|
||||
$this->assertNotEquals($userId1, $userId2);
|
||||
|
||||
// Test valid characters
|
||||
$this->assertMatchesRegularExpression('/^[a-f0-9]+$/', $userId1);
|
||||
$this->assertMatchesRegularExpression('/^[a-f0-9]+$/', $userId2);
|
||||
}
|
||||
|
||||
public function testGetClientIP()
|
||||
{
|
||||
// Test with default server vars
|
||||
$ip = Security::getClientIP();
|
||||
$this->assertEquals('127.0.0.1', $ip);
|
||||
|
||||
// Test with forwarded headers
|
||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = '192.168.1.100, 10.0.0.1';
|
||||
$ip = Security::getClientIP();
|
||||
$this->assertEquals('192.168.1.100', $ip);
|
||||
|
||||
// Test with real IP header
|
||||
$_SERVER['HTTP_X_REAL_IP'] = '203.0.113.1';
|
||||
unset($_SERVER['HTTP_X_FORWARDED_FOR']);
|
||||
$ip = Security::getClientIP();
|
||||
$this->assertEquals('203.0.113.1', $ip);
|
||||
}
|
||||
|
||||
public function testSanitizeInput()
|
||||
{
|
||||
// Test string sanitization
|
||||
$input = '<script>alert("xss")</script>Hello World';
|
||||
$result = Security::sanitizeInput($input, 'string');
|
||||
$this->assertEquals('alert("xss")Hello World', $result);
|
||||
|
||||
// Test email sanitization
|
||||
$email = 'test@example.com<script>evil</script>';
|
||||
$result = Security::sanitizeInput($email, 'email');
|
||||
$this->assertEquals('test@example.com<script>evil</script>', $result);
|
||||
|
||||
// Test URL sanitization
|
||||
$url = 'http://example.com/path<script>evil</script>';
|
||||
$result = Security::sanitizeInput($url, 'url');
|
||||
$this->assertEquals('http://example.com/path', $result); // Scripts should be stripped
|
||||
}
|
||||
|
||||
public function testValidateCSRFToken()
|
||||
{
|
||||
// Generate a token
|
||||
$token = Security::generateCSRFToken();
|
||||
$_SESSION['csrf_token'] = $token;
|
||||
|
||||
// Test valid token
|
||||
$this->assertTrue(Security::validateCSRFToken($token));
|
||||
|
||||
// Test invalid token
|
||||
$this->assertFalse(Security::validateCSRFToken('invalid_token'));
|
||||
|
||||
// Test missing token
|
||||
$this->assertFalse(Security::validateCSRFToken(''));
|
||||
}
|
||||
|
||||
public function testCheckRateLimit()
|
||||
{
|
||||
$ip = '192.168.1.100';
|
||||
|
||||
// First request should succeed
|
||||
$result1 = Security::checkRateLimit($ip, 'test_action', 3, 60);
|
||||
$this->assertTrue($result1);
|
||||
|
||||
// Second request should succeed
|
||||
$result2 = Security::checkRateLimit($ip, 'test_action', 3, 60);
|
||||
$this->assertTrue($result2);
|
||||
|
||||
// Third request should succeed
|
||||
$result3 = Security::checkRateLimit($ip, 'test_action', 3, 60);
|
||||
$this->assertTrue($result3);
|
||||
|
||||
// Fourth request should fail (over limit)
|
||||
$result4 = Security::checkRateLimit($ip, 'test_action', 3, 60);
|
||||
$this->assertFalse($result4);
|
||||
}
|
||||
|
||||
public function testIsValidStreamUrl()
|
||||
{
|
||||
// Valid URLs
|
||||
$this->assertTrue(Security::isValidStreamUrl('http://127.0.0.1:8080/stream'));
|
||||
$this->assertTrue(Security::isValidStreamUrl('https://127.0.0.1:8080/stream'));
|
||||
$this->assertTrue(Security::isValidStreamUrl('http://localhost:8080/stream'));
|
||||
|
||||
// Invalid URLs
|
||||
$this->assertFalse(Security::isValidStreamUrl('http://evil.com/stream'));
|
||||
$this->assertFalse(Security::isValidStreamUrl('http://192.168.1.1/stream'));
|
||||
$this->assertFalse(Security::isValidStreamUrl('javascript:alert(1)'));
|
||||
$this->assertFalse(Security::isValidStreamUrl(''));
|
||||
}
|
||||
|
||||
public function testAdminAuthentication()
|
||||
{
|
||||
// Test without any auth setup
|
||||
$this->assertFalse(Security::isAdminAuthenticated());
|
||||
|
||||
// Set up session auth
|
||||
$_SESSION['admin_authenticated'] = true;
|
||||
$_SESSION['admin_login_time'] = time();
|
||||
|
||||
$this->assertTrue(Security::isAdminAuthenticated());
|
||||
}
|
||||
|
||||
public function testAuthenticateAdmin()
|
||||
{
|
||||
// This would need proper config setup for real testing
|
||||
// For now, test that the method exists and handles failures
|
||||
$result = Security::authenticateAdmin('invalid_user', 'invalid_pass');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testDetectSuspiciousActivity()
|
||||
{
|
||||
// Test with normal request
|
||||
$warnings = Security::detectSuspiciousActivity();
|
||||
$this->assertIsArray($warnings);
|
||||
|
||||
// Test with suspicious user agent
|
||||
$_SERVER['HTTP_USER_AGENT'] = 'sqlmap';
|
||||
$warnings = Security::detectSuspiciousActivity();
|
||||
$this->assertContains('Suspicious user agent detected', $warnings);
|
||||
|
||||
// Reset
|
||||
$_SERVER['HTTP_USER_AGENT'] = 'PHPUnit/Test';
|
||||
}
|
||||
|
||||
public function testLogSecurityEvent()
|
||||
{
|
||||
// Start output buffering to capture logs
|
||||
ob_start();
|
||||
|
||||
// Generate a security event
|
||||
Security::logSecurityEvent('test_event', ['test_data' => 'value']);
|
||||
|
||||
// The actual logging happens in ErrorHandler, so we test that no exceptions are thrown
|
||||
$this->assertTrue(true);
|
||||
|
||||
ob_end_clean();
|
||||
}
|
||||
}
|
||||
215
tests/unit/UserModelTest.php
Normal file
215
tests/unit/UserModelTest.php
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test UserModel database operations
|
||||
*/
|
||||
class UserModelTest extends TestCase
|
||||
{
|
||||
private $userModel;
|
||||
private $testUserId;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
// Set up in-memory database for testing
|
||||
TestDatabaseHelper::setupTestSchema();
|
||||
$this->userModel = new UserModel();
|
||||
$this->testUserId = 'test_user_' . bin2hex(random_bytes(8));
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
// Clean up after each test
|
||||
$pdo = TestDatabaseHelper::getTestPdo();
|
||||
$pdo->exec('DELETE FROM users');
|
||||
$pdo->exec('DELETE FROM chat_messages');
|
||||
$pdo->exec('DELETE FROM active_viewers');
|
||||
$pdo->exec('DELETE FROM banned_users');
|
||||
}
|
||||
|
||||
public function testCreateOrUpdateNewUser()
|
||||
{
|
||||
$userData = [
|
||||
'nickname' => 'TestUser',
|
||||
'ip_address' => '192.168.1.100',
|
||||
'session_id' => 'session_123456'
|
||||
];
|
||||
|
||||
$result = $this->userModel->createOrUpdate($this->testUserId, $userData);
|
||||
|
||||
$this->assertNotFalse($result);
|
||||
|
||||
// Verify user was created
|
||||
$user = $this->userModel->getByUserId($this->testUserId);
|
||||
$this->assertNotFalse($user);
|
||||
$this->assertEquals($this->testUserId, $user['user_id']);
|
||||
$this->assertEquals('TestUser', $user['nickname']);
|
||||
$this->assertEquals('192.168.1.100', $user['ip_address']);
|
||||
}
|
||||
|
||||
public function testCreateOrUpdateExistingUser()
|
||||
{
|
||||
// First create user
|
||||
$this->userModel->createOrUpdate($this->testUserId, ['nickname' => 'OriginalName']);
|
||||
|
||||
// Update existing user
|
||||
$this->userModel->createOrUpdate($this->testUserId, ['nickname' => 'UpdatedName']);
|
||||
|
||||
$user = $this->userModel->getByUserId($this->testUserId);
|
||||
$this->assertEquals('UpdatedName', $user['nickname']);
|
||||
}
|
||||
|
||||
public function testGetActiveUsers()
|
||||
{
|
||||
// Create test users
|
||||
$userId1 = 'active_user_1';
|
||||
$userId2 = 'active_user_2';
|
||||
$userId3 = 'inactive_user';
|
||||
|
||||
// Add active users
|
||||
$this->userModel->createOrUpdate($userId1, ['nickname' => 'Active1']);
|
||||
$this->userModel->createOrUpdate($userId2, ['nickname' => 'Active2']);
|
||||
$this->userModel->createOrUpdate($userId3, ['nickname' => 'Inactive']);
|
||||
|
||||
// Simulate inactive user (old timestamp)
|
||||
$pdo = TestDatabaseHelper::getTestPdo();
|
||||
$pdo->exec("UPDATE users SET last_seen = datetime('now', '-40 seconds') WHERE user_id = '$userId3'");
|
||||
|
||||
$activeUsers = $this->userModel->getActiveUsers(30);
|
||||
|
||||
$this->assertCount(2, $activeUsers);
|
||||
|
||||
// Verify active users are returned
|
||||
$userIds = array_column($activeUsers, 'user_id');
|
||||
$this->assertContains($userId1, $userIds);
|
||||
$this->assertContains($userId2, $userIds);
|
||||
$this->assertNotContains($userId3, $userIds);
|
||||
}
|
||||
|
||||
public function testUpdateLastSeen()
|
||||
{
|
||||
// Create user
|
||||
$this->userModel->createOrUpdate($this->testUserId, ['nickname' => 'TestUser']);
|
||||
|
||||
// Get initial last_seen
|
||||
$user = $this->userModel->getByUserId($this->testUserId);
|
||||
$initialLastSeen = $user['last_seen'];
|
||||
|
||||
// Wait a moment to ensure different timestamp
|
||||
sleep(1);
|
||||
|
||||
// Update last seen
|
||||
$result = $this->userModel->updateLastSeen($this->testUserId);
|
||||
$this->assertNotFalse($result);
|
||||
|
||||
// Verify last seen was updated
|
||||
$updatedUser = $this->userModel->getByUserId($this->testUserId);
|
||||
$this->assertNotEquals($initialLastSeen, $updatedUser['last_seen']);
|
||||
}
|
||||
|
||||
public function testBanAndUnbanUser()
|
||||
{
|
||||
// Create user first
|
||||
$this->userModel->createOrUpdate($this->testUserId, ['nickname' => 'TestUser']);
|
||||
|
||||
// Test initial state - not banned
|
||||
$this->assertFalse($this->userModel->isBanned($this->testUserId));
|
||||
|
||||
// Ban user
|
||||
$result = $this->userModel->banUser($this->testUserId, 'admin_user', 'Test ban reason');
|
||||
$this->assertNotFalse($result);
|
||||
|
||||
// Verify user is banned
|
||||
$this->assertTrue($this->userModel->isBanned($this->testUserId));
|
||||
|
||||
// Get banned users list
|
||||
$bannedUsers = $this->userModel->getBannedUsers();
|
||||
$this->assertCount(1, $bannedUsers);
|
||||
$this->assertEquals($this->testUserId, $bannedUsers[0]['user_id']);
|
||||
$this->assertEquals('Test ban reason', $bannedUsers[0]['reason']);
|
||||
|
||||
// Unban user
|
||||
$result = $this->userModel->unbanUser($this->testUserId);
|
||||
$this->assertNotFalse($result);
|
||||
|
||||
// Verify user is no longer banned
|
||||
$this->assertFalse($this->userModel->isBanned($this->testUserId));
|
||||
|
||||
// Verify banned users list is empty
|
||||
$bannedUsers = $this->userModel->getBannedUsers();
|
||||
$this->assertCount(0, $bannedUsers);
|
||||
}
|
||||
|
||||
public function testUpdateNickname()
|
||||
{
|
||||
// Create user
|
||||
$this->userModel->createOrUpdate($this->testUserId, ['nickname' => 'OldName']);
|
||||
|
||||
// Update nickname
|
||||
$result = $this->userModel->updateNickname($this->testUserId, 'NewName');
|
||||
$this->assertNotFalse($result);
|
||||
|
||||
// Verify nickname was updated
|
||||
$user = $this->userModel->getByUserId($this->testUserId);
|
||||
$this->assertEquals('NewName', $user['nickname']);
|
||||
}
|
||||
|
||||
public function testCleanupOldRecords()
|
||||
{
|
||||
// Create user
|
||||
$this->userModel->createOrUpdate($this->testUserId, ['nickname' => 'TestUser']);
|
||||
|
||||
// Set last_seen to be very old
|
||||
$pdo = TestDatabaseHelper::getTestPdo();
|
||||
$pdo->exec("UPDATE users SET last_seen = datetime('now', '-40 days') WHERE user_id = '$this->testUserId'");
|
||||
|
||||
// Cleanup records older than 30 days
|
||||
$result = $this->userModel->cleanupOldRecords(30);
|
||||
$this->assertGreaterThan(0, $result); // Should have deleted at least one record
|
||||
|
||||
// Verify user was cleaned up
|
||||
$user = $this->userModel->getByUserId($this->testUserId);
|
||||
$this->assertFalse($user);
|
||||
}
|
||||
|
||||
public function testNonExistentUser()
|
||||
{
|
||||
$user = $this->userModel->getByUserId('nonexistent_user');
|
||||
$this->assertFalse($user);
|
||||
|
||||
// Test update on non-existent user
|
||||
$result = $this->userModel->updateLastSeen('nonexistent_user');
|
||||
$this->assertEquals(0, $result); // No rows affected
|
||||
}
|
||||
|
||||
public function testGetActiveUsersWithinTimeframe()
|
||||
{
|
||||
// Create users with different activity times
|
||||
$userId1 = 'recent_user';
|
||||
$userId2 = 'old_user';
|
||||
|
||||
$this->userModel->createOrUpdate($userId1, ['nickname' => 'Recent']);
|
||||
$this->userModel->createOrUpdate($userId2, ['nickname' => 'Old']);
|
||||
|
||||
// Make one user appear old
|
||||
$pdo = TestDatabaseHelper::getTestPdo();
|
||||
$pdo->exec("UPDATE users SET last_seen = datetime('now', '-1 hour') WHERE user_id = '$userId2'");
|
||||
|
||||
// Get users active within 30 minutes
|
||||
$activeUsers = $this->userModel->getActiveUsers(30); // 30 seconds for testing
|
||||
$this->assertCount(1, $activeUsers);
|
||||
$this->assertEquals($userId1, $activeUsers[0]['user_id']);
|
||||
}
|
||||
|
||||
public function testDatabaseConnectionFailure()
|
||||
{
|
||||
// This test would verify error handling in a real scenario
|
||||
// For now, we test that the model handles database operations gracefully
|
||||
$this->assertIsObject($this->userModel);
|
||||
|
||||
// Test that methods return false/null on failure rather than throwing exceptions
|
||||
$result = $this->userModel->getByUserId('invalid_id_format_x');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
}
|
||||
222
tests/unit/ValidationTest.php
Normal file
222
tests/unit/ValidationTest.php
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test Validation utility functions
|
||||
*/
|
||||
class ValidationTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
// Clear any previous test data
|
||||
$_POST = [];
|
||||
$_GET = [];
|
||||
}
|
||||
|
||||
public function testValidateUserId()
|
||||
{
|
||||
// Valid user IDs
|
||||
$result = Validation::validateUserId('a1b2c3d4e5f67890123456789012abcd');
|
||||
$this->assertTrue($result['valid']);
|
||||
$this->assertEquals('a1b2c3d4e5f67890123456789012abcd', $result['user_id']);
|
||||
|
||||
// Invalid user IDs
|
||||
$result = Validation::validateUserId('invalid_user_id');
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateUserId('a1b2c3d4'); // Too short
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateUserId('a1b2c3d4e5f67890123456789012abcdextra'); // Too long
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateUserId('gggggggggggggggggggggggggggggggg'); // Invalid chars
|
||||
$this->assertFalse($result['valid']);
|
||||
}
|
||||
|
||||
public function testValidateNickname()
|
||||
{
|
||||
// Valid nicknames
|
||||
$result = Validation::validateNickname('JohnDoe');
|
||||
$this->assertTrue($result['valid']);
|
||||
|
||||
$result = Validation::validateNickname('Test User');
|
||||
$this->assertTrue($result['valid']);
|
||||
|
||||
$result = Validation::validateNickname("O'Connor-Smith");
|
||||
$this->assertTrue($result['valid']);
|
||||
|
||||
// Invalid nicknames
|
||||
$result = Validation::validateNickname(''); // Empty
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateNickname('A'); // Too short
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateNickname(str_repeat('A', 21)); // Too long
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateNickname('Invalid@Name'); // Invalid chars
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateNickname('<script>evil</script>'); // XSS attempt
|
||||
$this->assertFalse($result['valid']);
|
||||
}
|
||||
|
||||
public function testValidateMessage()
|
||||
{
|
||||
// Valid messages
|
||||
$result = Validation::validateMessage('Hello World!');
|
||||
$this->assertTrue($result['valid']);
|
||||
|
||||
$result = Validation::validateMessage('This is a longer message with punctuation, numbers 123, and symbols @#$%!');
|
||||
$this->assertTrue($result['valid']);
|
||||
|
||||
// Invalid messages
|
||||
$result = Validation::validateMessage(''); // Empty
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateMessage(str_repeat('A', 1001)); // Too long
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateMessage('<script>alert("xss")</script>'); // XSS
|
||||
$this->assertFalse($result['valid']);
|
||||
}
|
||||
|
||||
public function testValidateMessageSend()
|
||||
{
|
||||
// Valid message send data
|
||||
$data = [
|
||||
'nickname' => 'TestUser',
|
||||
'message' => 'Hello World!',
|
||||
'user_agent' => 'Mozilla/5.0 (Test Browser)',
|
||||
'ip_address' => '192.168.1.1'
|
||||
];
|
||||
|
||||
$result = Validation::validateMessageSend($data);
|
||||
$this->assertTrue($result['valid']);
|
||||
$this->assertEquals($data['nickname'], $result['validated']['nickname']);
|
||||
$this->assertEquals($data['message'], $result['validated']['message']);
|
||||
|
||||
// Invalid message send data
|
||||
$invalidData = [
|
||||
'nickname' => 'Invalid@Name',
|
||||
'message' => '<script>evil</script>',
|
||||
];
|
||||
|
||||
$result = Validation::validateMessageSend($invalidData);
|
||||
$this->assertFalse($result['valid']);
|
||||
$this->assertArrayHasKey('errors', $result);
|
||||
}
|
||||
|
||||
public function testValidateHeartbeat()
|
||||
{
|
||||
// Valid heartbeat data
|
||||
$data = [
|
||||
'nickname' => 'TestUser',
|
||||
'user_id' => 'a1b2c3d4e5f67890123456789012abcd',
|
||||
'session_id' => 'session_123456'
|
||||
];
|
||||
|
||||
$result = Validation::validateHeartbeat($data);
|
||||
$this->assertTrue($result['valid']);
|
||||
$this->assertEquals($data['nickname'], $result['validated']['nickname']);
|
||||
|
||||
// Invalid heartbeat data
|
||||
$invalidData = [
|
||||
'nickname' => str_repeat('A', 21), // Too long
|
||||
'user_id' => 'invalid_id',
|
||||
];
|
||||
|
||||
$result = Validation::validateHeartbeat($invalidData);
|
||||
$this->assertFalse($result['valid']);
|
||||
$this->assertArrayHasKey('errors', $result);
|
||||
}
|
||||
|
||||
public function testValidateAdminLogin()
|
||||
{
|
||||
// Valid login data
|
||||
$result = Validation::validateAdminLogin('admin_user', 'valid_password');
|
||||
$this->assertTrue($result['valid']);
|
||||
$this->assertEquals('admin_user', $result['data']['username']);
|
||||
|
||||
// Invalid login data
|
||||
$result = Validation::validateAdminLogin('', 'password'); // Empty username
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateAdminLogin('admin', ''); // Empty password
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateAdminLogin('us', 'password'); // Username too short
|
||||
$this->assertFalse($result['valid']);
|
||||
|
||||
$result = Validation::validateAdminLogin('user@domain.com', 'password'); // Invalid username format
|
||||
$this->assertFalse($result['valid']);
|
||||
}
|
||||
|
||||
public function testIsValidEmail()
|
||||
{
|
||||
// Valid emails
|
||||
$this->assertTrue(Validation::isValidEmail('user@example.com'));
|
||||
$this->assertTrue(Validation::isValidEmail('test.user+tag@example.co.uk'));
|
||||
$this->assertTrue(Validation::isValidEmail('user@localhost'));
|
||||
|
||||
// Invalid emails
|
||||
$this->assertFalse(Validation::isValidEmail('invalid-email'));
|
||||
$this->assertFalse(Validation::isValidEmail('user@'));
|
||||
$this->assertFalse(Validation::isValidEmail('@example.com'));
|
||||
$this->assertFalse(Validation::isValidEmail('user@.com'));
|
||||
}
|
||||
|
||||
public function testIsValidURL()
|
||||
{
|
||||
// Valid URLs
|
||||
$this->assertTrue(Validation::isValidURL('http://example.com'));
|
||||
$this->assertTrue(Validation::isValidURL('https://example.com/path?query=1'));
|
||||
$this->assertTrue(Validation::isValidURL('ftp://example.com/file.txt'));
|
||||
|
||||
// Invalid URLs
|
||||
$this->assertFalse(Validation::isValidURL('not-a-url'));
|
||||
$this->assertFalse(Validation::isValidURL('javascript:alert(1)'));
|
||||
$this->assertFalse(Validation::isValidURL(''));
|
||||
}
|
||||
|
||||
public function testCleanString()
|
||||
{
|
||||
// Test normal cleaning
|
||||
$result = Validation::cleanString(' Hello World ');
|
||||
$this->assertEquals('Hello World', $result);
|
||||
|
||||
// Test with HTML entities
|
||||
$result = Validation::cleanString('Hello & World <tag>');
|
||||
$this->assertEquals('Hello & World <tag>', $result);
|
||||
|
||||
// Test with script tags (should be encoded)
|
||||
$result = Validation::cleanString('<script>alert(1)</script>Hello');
|
||||
$this->assertEquals('<script>alert(1)</script>Hello', $result);
|
||||
}
|
||||
|
||||
public function testLengthBetween()
|
||||
{
|
||||
// Test valid lengths
|
||||
$this->assertTrue(Validation::lengthBetween('test', 2, 10));
|
||||
$this->assertTrue(Validation::lengthBetween('test', 4, 4));
|
||||
|
||||
// Test invalid lengths
|
||||
$this->assertFalse(Validation::lengthBetween('t', 2, 10)); // Too short
|
||||
$this->assertFalse(Validation::lengthBetween('this_is_a_very_long_string', 2, 10)); // Too long
|
||||
}
|
||||
|
||||
public function testMatchesPattern()
|
||||
{
|
||||
// Test valid patterns
|
||||
$this->assertTrue(Validation::matchesPattern('123', '/^\d+$/'));
|
||||
$this->assertTrue(Validation::matchesPattern('abc123', '/^[a-zA-Z0-9]+$/'));
|
||||
$this->assertTrue(Validation::matchesPattern('test@example.com', '/^[^\s@]+@[^\s@]+\.[^\s@]+$/')); // Simple email regex
|
||||
|
||||
// Test invalid patterns
|
||||
$this->assertFalse(Validation::matchesPattern('abc', '/^\d+$/')); // Not numeric
|
||||
$this->assertFalse(Validation::matchesPattern('invalid-email', '/^[^\s@]+@[^\s@]+\.[^\s@]+$/')); // Not email
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue