2 - Add InstanceConfig value object and InstanceType enum

This commit is contained in:
myrmidex 2026-04-23 23:03:06 +02:00
parent 7a2db5a14d
commit bdd2b0f2e5
4 changed files with 199 additions and 3 deletions

View file

@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace Lvl0\FediDiscover\Config;
use InvalidArgumentException;
final readonly class InstanceConfig
{
/**
* @param array<string, mixed> $extras
*/
public function __construct(
public InstanceType $type,
public string $url,
public bool $enabled,
public int $intervalSeconds,
public array $extras
) {}
/**
* @throws InvalidArgumentException
*/
public static function fromArray(array $array): self
{
foreach (['type', 'url', 'enabled', 'interval_seconds'] as $key) {
if (! array_key_exists($key, $array)) {
throw new InvalidArgumentException("Missing required key: {$key}");
}
}
if ($array['interval_seconds'] <= 0) {
throw new InvalidArgumentException('Interval seconds needs to be larger than zero');
}
$type = InstanceType::tryFrom($array['type']);
if ($type === null) {
throw new InvalidArgumentException('Invalid type: ' . $array['type']);
}
if (filter_var($array['url'], FILTER_VALIDATE_URL) === false) {
throw new InvalidArgumentException('Invalid URL: ' . $array['url']);
}
return new self(
type: $type,
url: $array['url'],
enabled: $array['enabled'],
intervalSeconds: $array['interval_seconds'],
extras: $array['extras'] ?? []
);
}
public function toArray(): array
{
return [
'type' => $this->type->value,
'url' => $this->url,
'enabled' => $this->enabled,
'interval_seconds' => $this->intervalSeconds,
'extras' => $this->extras,
];
}
}

View file

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Lvl0\FediDiscover\Config;
enum InstanceType: string
{
case Mastodon = 'mastodon';
}

View file

@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace Lvl0\FediDiscover\Tests\Unit;
use Lvl0\FediDiscover\Config\InstanceConfig;
use Lvl0\FediDiscover\Config\InstanceType;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class InstanceConfigTest extends TestCase
{
public function test_from_array_returns_instance_config_with_correct_field_values(): void
{
$config = InstanceConfig::fromArray([
'type' => 'mastodon',
'url' => 'https://mastodon.social',
'enabled' => true,
'interval_seconds' => 600,
'extras' => ['token' => 'abc123'],
]);
$this->assertSame(InstanceType::Mastodon, $config->type);
$this->assertSame('https://mastodon.social', $config->url);
$this->assertTrue($config->enabled);
$this->assertSame(600, $config->intervalSeconds);
$this->assertSame(['token' => 'abc123'], $config->extras);
}
public function test_from_array_rejects_non_positive_interval_seconds(): void
{
$this->expectException(\InvalidArgumentException::class);
InstanceConfig::fromArray([
'type' => 'mastodon',
'url' => 'https://mastodon.social',
'enabled' => true,
'interval_seconds' => 0,
'extras' => [],
]);
}
public function test_extras_defaults_to_empty_array_when_omitted(): void
{
$config = InstanceConfig::fromArray([
'type' => 'mastodon',
'url' => 'https://mastodon.social',
'enabled' => true,
'interval_seconds' => 600,
]);
$this->assertSame([], $config->extras);
}
#[DataProvider('requiredKeyProvider')]
public function test_from_array_throws_when_required_key_is_missing(string $missingKey): void
{
$input = [
'type' => 'mastodon',
'url' => 'https://mastodon.social',
'enabled' => true,
'interval_seconds' => 600,
];
unset($input[$missingKey]);
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessageMatches('/' . preg_quote($missingKey, '/') . '/');
InstanceConfig::fromArray($input);
}
public static function requiredKeyProvider(): array
{
return [
'type missing' => ['type'],
'url missing' => ['url'],
'enabled missing' => ['enabled'],
'interval_seconds missing' => ['interval_seconds'],
];
}
public function test_from_array_throws_invalid_argument_exception_for_unknown_type_string(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessageMatches('/pleroma/');
InstanceConfig::fromArray([
'type' => 'pleroma',
'url' => 'https://pleroma.example.com',
'enabled' => true,
'interval_seconds' => 600,
]);
}
public function test_from_array_rejects_malformed_url(): void
{
$this->expectException(\InvalidArgumentException::class);
InstanceConfig::fromArray([
'type' => 'mastodon',
'url' => 'not a url',
'enabled' => true,
'interval_seconds' => 600,
]);
}
public function test_to_array_produces_array_that_round_trips_through_from_array(): void
{
$original = [
'type' => 'mastodon',
'url' => 'https://mastodon.social',
'enabled' => true,
'interval_seconds' => 600,
'extras' => ['token' => 'abc123'],
];
$this->assertSame($original, InstanceConfig::fromArray($original)->toArray());
}
}