mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-26 03:03:12 +01:00
test(core): unit tests for Util/Database/Enum pure logic (+44 tests)
Adds tests for Encryption, TimeUtils, QueryHelper, AdminHelpers, ImageUtils, StreamUtils and BootContext/ServerEnvironment enums. 242 -> 286 tests, all green.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers AdminHelpers
|
||||
*/
|
||||
final class AdminHelpersTest extends TestCase {
|
||||
|
||||
public function testValidateCidrAcceptsValidAddressesAndMasks() {
|
||||
$this->assertTrue(AdminHelpers::validateCIDR('192.168.1.1'));
|
||||
$this->assertTrue(AdminHelpers::validateCIDR('192.168.1.0/24'));
|
||||
$this->assertTrue(AdminHelpers::validateCIDR('::1'));
|
||||
}
|
||||
|
||||
public function testValidateCidrRejectsInvalidInput() {
|
||||
$this->assertFalse(AdminHelpers::validateCIDR('not-an-ip'));
|
||||
$this->assertFalse(AdminHelpers::validateCIDR('10.0.0.0/33'));
|
||||
$this->assertFalse(AdminHelpers::validateCIDR('2001:db8::/129'));
|
||||
}
|
||||
|
||||
public function testRoundUpToAny() {
|
||||
$this->assertEquals(10, AdminHelpers::roundUpToAny(7, 5));
|
||||
$this->assertEquals(15, AdminHelpers::roundUpToAny(13, 5));
|
||||
$this->assertEquals(5, AdminHelpers::roundUpToAny(3, 5));
|
||||
}
|
||||
|
||||
public function testGenerateStringLengthAndUnambiguousCharset() {
|
||||
$charset = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ';
|
||||
$s = AdminHelpers::generateString(16);
|
||||
$this->assertSame(16, strlen($s));
|
||||
$this->assertSame(strlen($s), strspn($s, $charset));
|
||||
}
|
||||
|
||||
public function testSortArrayByArray() {
|
||||
$this->assertSame(
|
||||
array('c', 'b', 'a'),
|
||||
AdminHelpers::sortArrayByArray(array('a', 'b', 'c'), array('c', 'b', 'a'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetBarColourThresholds() {
|
||||
$this->assertSame('bg-danger', AdminHelpers::getBarColour(80));
|
||||
$this->assertSame('bg-danger', AdminHelpers::getBarColour(75));
|
||||
$this->assertSame('bg-warning', AdminHelpers::getBarColour(50));
|
||||
$this->assertSame('bg-success', AdminHelpers::getBarColour(10));
|
||||
}
|
||||
|
||||
public function testFormatUptime() {
|
||||
$this->assertSame('01h 01m 01s', AdminHelpers::formatUptime(3661));
|
||||
$this->assertSame('01d 01h 00m', AdminHelpers::formatUptime(90000));
|
||||
}
|
||||
|
||||
public function testFilterIdsKeepsOnlyAllowedPositiveInts() {
|
||||
$this->assertSame(
|
||||
array(1, 2),
|
||||
AdminHelpers::filterIDs(array('1', '2', 'x', 5), array(1, 2, 3))
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetPageFromUrl() {
|
||||
$this->assertSame('bouquet', AdminHelpers::getPageFromURL('http://host/admin/bouquet.php'));
|
||||
$this->assertNull(AdminHelpers::getPageFromURL(''));
|
||||
}
|
||||
|
||||
public function testProtocolDetectionFromServerVars() {
|
||||
$saved = $_SERVER;
|
||||
|
||||
$_SERVER['HTTPS'] = 'on';
|
||||
$this->assertTrue(AdminHelpers::issecure());
|
||||
$this->assertSame('https', AdminHelpers::getProtocol());
|
||||
|
||||
unset($_SERVER['HTTPS']);
|
||||
$_SERVER['SERVER_PORT'] = 80;
|
||||
$this->assertFalse(AdminHelpers::issecure());
|
||||
$this->assertSame('http', AdminHelpers::getProtocol());
|
||||
|
||||
$_SERVER['SERVER_PORT'] = 443;
|
||||
$this->assertTrue(AdminHelpers::issecure());
|
||||
|
||||
$_SERVER = $saved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers BootContext
|
||||
* @covers ServerEnvironment
|
||||
*/
|
||||
final class CoreEnumTest extends TestCase {
|
||||
|
||||
public function testBootContextValues() {
|
||||
$this->assertSame('minimal', BootContext::Minimal->value);
|
||||
$this->assertSame('cli', BootContext::Cli->value);
|
||||
$this->assertSame('stream', BootContext::Stream->value);
|
||||
$this->assertSame('admin', BootContext::Admin->value);
|
||||
}
|
||||
|
||||
public function testBootContextFromString() {
|
||||
$this->assertSame(BootContext::Admin, BootContext::from('admin'));
|
||||
$this->assertNull(BootContext::tryFrom('nope'));
|
||||
$this->assertCount(4, BootContext::cases());
|
||||
}
|
||||
|
||||
public function testServerEnvironmentValues() {
|
||||
$this->assertSame('main', ServerEnvironment::Main->value);
|
||||
$this->assertSame('lb', ServerEnvironment::LoadBalancer->value);
|
||||
}
|
||||
|
||||
public function testServerEnvironmentFromString() {
|
||||
$this->assertSame(ServerEnvironment::LoadBalancer, ServerEnvironment::from('lb'));
|
||||
$this->assertNull(ServerEnvironment::tryFrom('xxx'));
|
||||
$this->assertCount(2, ServerEnvironment::cases());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers Encryption
|
||||
*/
|
||||
final class EncryptionTest extends TestCase {
|
||||
|
||||
public function testEncryptDecryptRoundTrip() {
|
||||
$plain = 'hello world / стрим 123';
|
||||
$cipher = Encryption::encrypt($plain, 'secret-key', 'device-1');
|
||||
|
||||
$this->assertNotSame($plain, $cipher);
|
||||
$this->assertSame($plain, Encryption::decrypt($cipher, 'secret-key', 'device-1'));
|
||||
}
|
||||
|
||||
public function testEncryptIsDeterministicForSameInputs() {
|
||||
// Same data/key/device → same ciphertext (derived key + IV are deterministic).
|
||||
$a = Encryption::encrypt('data', 'k', 'd');
|
||||
$b = Encryption::encrypt('data', 'k', 'd');
|
||||
$this->assertSame($a, $b);
|
||||
}
|
||||
|
||||
public function testDecryptWithWrongKeyFails() {
|
||||
$cipher = Encryption::encrypt('secret', 'right-key', 'device');
|
||||
$this->assertFalse(Encryption::decrypt($cipher, 'wrong-key', 'device'));
|
||||
}
|
||||
|
||||
public function testDecryptWithWrongDeviceFails() {
|
||||
$cipher = Encryption::encrypt('secret', 'key', 'device-a');
|
||||
$this->assertFalse(Encryption::decrypt($cipher, 'key', 'device-b'));
|
||||
}
|
||||
|
||||
public function testBase64urlIsUrlSafeAndUnpadded() {
|
||||
$raw = "\xff\xfe\xfd\x00binary?";
|
||||
$encoded = Encryption::base64urlEncode($raw);
|
||||
|
||||
$this->assertStringNotContainsString('+', $encoded);
|
||||
$this->assertStringNotContainsString('/', $encoded);
|
||||
$this->assertStringNotContainsString('=', $encoded);
|
||||
$this->assertSame($raw, Encryption::base64urlDecode($encoded));
|
||||
}
|
||||
|
||||
public function testRandomStringLengthAndCharset() {
|
||||
$s = Encryption::randomString(40);
|
||||
$this->assertSame(40, strlen($s));
|
||||
$this->assertMatchesRegularExpression('/^[A-Za-z0-9]+$/', $s);
|
||||
}
|
||||
|
||||
public function testRandomTokenLengthIsHex() {
|
||||
$token = Encryption::randomToken(16);
|
||||
$this->assertSame(32, strlen($token));
|
||||
$this->assertMatchesRegularExpression('/^[0-9a-f]+$/', $token);
|
||||
}
|
||||
|
||||
public function testGenerateKeyByteLength() {
|
||||
$this->assertSame(16, strlen(Encryption::generateKey(128)));
|
||||
$this->assertSame(32, strlen(Encryption::generateKey(256)));
|
||||
}
|
||||
|
||||
public function testGenerateIvLengthForAes128() {
|
||||
$this->assertSame(16, strlen(Encryption::generateIV('AES-128-CBC')));
|
||||
}
|
||||
|
||||
public function testGenerateUniqueCodeIsStable15Chars() {
|
||||
$code = Encryption::generateUniqueCode('pass');
|
||||
$this->assertSame(15, strlen($code));
|
||||
$this->assertSame($code, Encryption::generateUniqueCode('pass'));
|
||||
$this->assertNotSame($code, Encryption::generateUniqueCode('other'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers ImageUtils
|
||||
*/
|
||||
final class ImageUtilsTest extends TestCase {
|
||||
|
||||
public function testKeepAspectRatioDownscales() {
|
||||
$size = ImageUtils::getImageSizeKeepAspectRatio(1000, 500, 100, 100);
|
||||
$this->assertEquals(100, $size['width']);
|
||||
$this->assertEquals(50, $size['height']);
|
||||
}
|
||||
|
||||
public function testKeepAspectRatioDoesNotUpscale() {
|
||||
$size = ImageUtils::getImageSizeKeepAspectRatio(50, 50, 100, 100);
|
||||
$this->assertEquals(50, $size['width']);
|
||||
$this->assertEquals(50, $size['height']);
|
||||
}
|
||||
|
||||
public function testKeepAspectRatioTreatsZeroMaxAsUnbounded() {
|
||||
$size = ImageUtils::getImageSizeKeepAspectRatio(200, 100, 0, 50);
|
||||
$this->assertEquals(100, $size['width']);
|
||||
$this->assertEquals(50, $size['height']);
|
||||
}
|
||||
|
||||
public function testIsAbsoluteUrl() {
|
||||
$this->assertTrue(ImageUtils::isAbsoluteUrl('http://example.com/a.png'));
|
||||
$this->assertTrue(ImageUtils::isAbsoluteUrl('https://example.com/a.png'));
|
||||
$this->assertFalse(ImageUtils::isAbsoluteUrl('/relative/a.png'));
|
||||
$this->assertFalse(ImageUtils::isAbsoluteUrl('a.png'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers QueryHelper
|
||||
*/
|
||||
final class QueryHelperTest extends TestCase {
|
||||
|
||||
public function testPrepareColumnSanitizesToSafeIdentifier() {
|
||||
$this->assertSame('foobar23', QueryHelper::prepareColumn('Foo Bar!23'));
|
||||
$this->assertSame('user_id', QueryHelper::prepareColumn('user_id'));
|
||||
$this->assertSame('droptable', QueryHelper::prepareColumn('drop;table'));
|
||||
}
|
||||
|
||||
public function testPrepareArrayBuildsColumnsPlaceholdersAndData() {
|
||||
$result = QueryHelper::prepareArray(array('name' => 'x', 'age' => 5));
|
||||
|
||||
$this->assertSame('`name`,`age`', $result['columns']);
|
||||
$this->assertSame('?,?', $result['placeholder']);
|
||||
$this->assertSame(array('x', 5), $result['data']);
|
||||
$this->assertSame('`name` = ?,`age` = ?', $result['update']);
|
||||
}
|
||||
|
||||
public function testPrepareArrayJsonEncodesArrayValues() {
|
||||
$result = QueryHelper::prepareArray(array('tags' => array(1, 2, 3)));
|
||||
$this->assertSame('[1,2,3]', $result['data'][0]);
|
||||
}
|
||||
|
||||
public function testPrepareArrayNormalizesNullValues() {
|
||||
$result = QueryHelper::prepareArray(array('a' => null, 'b' => 'null'));
|
||||
$this->assertNull($result['data'][0]);
|
||||
$this->assertNull($result['data'][1]);
|
||||
}
|
||||
|
||||
public function testPrepareArraySanitizesColumnNames() {
|
||||
$result = QueryHelper::prepareArray(array('na me!' => 'v'));
|
||||
$this->assertSame('`name`', $result['columns']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers StreamUtils
|
||||
*/
|
||||
final class StreamUtilsTest extends TestCase {
|
||||
|
||||
public function testCustomOrderPutsInputArgumentsFirst() {
|
||||
$this->assertSame(-1, StreamUtils::customOrder('-i input.ts', 'something'));
|
||||
$this->assertSame(1, StreamUtils::customOrder('-c:v libx264', '-i input.ts'));
|
||||
}
|
||||
|
||||
public function testDetectXcVmMatchesKnownStreamPaths() {
|
||||
$this->assertTrue(StreamUtils::detectXC_VM('http://host/live/user/123'));
|
||||
}
|
||||
|
||||
public function testDetectXcVmRejectsUnrelatedPaths() {
|
||||
$this->assertFalse(StreamUtils::detectXC_VM('http://host/dashboard'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers TimeUtils
|
||||
*/
|
||||
final class TimeUtilsTest extends TestCase {
|
||||
|
||||
public function testSecondsToTimeWithSeconds() {
|
||||
$this->assertSame('1h 1m 1s', TimeUtils::secondsToTime(3661));
|
||||
$this->assertSame('1d 0s', TimeUtils::secondsToTime(86400));
|
||||
$this->assertSame('1m 30s', TimeUtils::secondsToTime(90));
|
||||
$this->assertSame('0s', TimeUtils::secondsToTime(0));
|
||||
}
|
||||
|
||||
public function testSecondsToTimeWithoutSeconds() {
|
||||
$this->assertSame('1h 1m', TimeUtils::secondsToTime(3661, false));
|
||||
$this->assertSame('1d', TimeUtils::secondsToTime(86400, false));
|
||||
}
|
||||
|
||||
public function testDurationToSecondsThreeParts() {
|
||||
$this->assertSame(3661, TimeUtils::durationToSeconds('01:01:01'));
|
||||
$this->assertSame(7200, TimeUtils::durationToSeconds('02:00:00'));
|
||||
}
|
||||
|
||||
public function testDurationToSecondsTwoParts() {
|
||||
$this->assertSame(90, TimeUtils::durationToSeconds('01:30'));
|
||||
}
|
||||
|
||||
public function testDurationToSecondsPlainNumber() {
|
||||
$this->assertSame(42, TimeUtils::durationToSeconds('42'));
|
||||
}
|
||||
|
||||
public function testTimeAgoBuckets() {
|
||||
$now = time();
|
||||
$this->assertStringEndsWith('s ago', TimeUtils::timeAgo($now - 5));
|
||||
$this->assertStringEndsWith('m ago', TimeUtils::timeAgo($now - 120));
|
||||
$this->assertStringEndsWith('h ago', TimeUtils::timeAgo($now - 7200));
|
||||
$this->assertStringEndsWith('d ago', TimeUtils::timeAgo($now - 172800));
|
||||
}
|
||||
|
||||
public function testNowMatchesFormat() {
|
||||
$this->assertMatchesRegularExpression('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', TimeUtils::now());
|
||||
$this->assertMatchesRegularExpression('/^\d{4}$/', TimeUtils::now('Y'));
|
||||
}
|
||||
|
||||
public function testGetDiffTimezoneReturnsInteger() {
|
||||
$diff = TimeUtils::getDiffTimezone('UTC');
|
||||
$this->assertIsInt($diff);
|
||||
// Both anchors are "now in UTC"; allow ±1s for a second-boundary race.
|
||||
$this->assertLessThanOrEqual(1, abs($diff));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user