getVerNum('v1.2.3')); self::assertNull($base->getVerNum('no-version')); } public function testGlobalValueSupportsCrudOperations(): void { $store = GlobalValue::getInstance(); $store->set('foo', 'bar'); self::assertTrue($store->has('foo')); self::assertSame('bar', $store->get('foo')); $store->del('foo'); self::assertFalse($store->has('foo')); self::assertSame('fallback', $store->get('foo', 'fallback')); } public function testCustomExceptionsEmbedFormattedMessagesAndCodes(): void { $this->setEnvValues([ 'CUSTOM_LANGUAGE' => 'zh', ]); $llf = new LlfException(34520002, 'boom'); $warning = new WarningException(34520014, ['demo@example.com', 'no domain']); self::assertStringContainsString('boom', $llf->getMessage()); self::assertStringContainsString('Error code: 34520002', $llf->getMessage()); self::assertStringContainsString('Warning code: 34520014', $warning->getMessage()); } public function testFreeNomProtectedParsingHelpersWorkOnExpectedMarkup(): void { $freenom = $this->newInstanceWithoutConstructor(FreeNom::class); $this->setProperty($freenom, 'username', 'demo@example.com'); $page = <<<'HTML'
  • Logout
  • alpha.tkActiveexpires 10 daysrenew
    beta.mlActiveexpires 20 daysrenew
    HTML; $domains = $this->invokeMethod($freenom, 'getAllDomains', [$page]); self::assertCount(2, $domains); self::assertSame('alpha.tk', $domains[0]['domain']); self::assertSame('10', $domains[0]['days']); self::assertSame('123', $domains[0]['id']); self::assertSame('token-123', $this->invokeMethod($freenom, 'getToken', [$page])); } public function testFreeNomArrayUniqueKeepsDistinctCredentialPairs(): void { $freenom = $this->newInstanceWithoutConstructor(FreeNom::class); $accounts = [ ['username' => 'ab', 'password' => 'c'], ['username' => 'a', 'password' => 'bc'], ['username' => 'ab', 'password' => 'c'], ]; self::assertTrue($freenom->arrayUnique($accounts)); self::assertCount(2, $accounts); } public function testUpgradeFormatsReleaseMessageWithoutHttpCalls(): void { $this->setEnvValues([ 'CUSTOM_LANGUAGE' => 'zh', ]); $upgrade = $this->newInstanceWithoutConstructor(Upgrade::class); $this->setProperty($upgrade, 'releaseInfo', [ 'published_at' => '2024-01-01T00:00:00Z', 'body' => "Line 1\nLine 2", 'html_url' => 'https://example.test/releases/v9.9.9', ]); $this->setProperty($upgrade, 'latestVer', '9.9.9'); $this->setProperty($upgrade, 'currVer', '0.6.2'); self::assertStringStartsWith('2024-01-01', $upgrade->friendlyDateFormat('2024-01-01T00:00:00Z', 'UTC')); self::assertStringContainsString('v9.9.9', $upgrade->genMsgContent()); self::assertStringContainsString('https://example.test/releases/v9.9.9', $upgrade->genMsgContent()); } public function testMigrateEnvFileEscapesStringValues(): void { $migrator = $this->newInstanceWithoutConstructor(MigrateEnvFile::class); self::assertSame("COUNT=1", $migrator->formatEnvVal('COUNT', 1)); self::assertSame("SECRET='a\\'b\\\\c\\nnext'", $migrator->formatEnvVal('SECRET', "a'b\\c\nnext")); } }