From bdd2b0f2e542df2551f439d82cee5ba813effde0 Mon Sep 17 00:00:00 2001 From: myrmidex Date: Thu, 23 Apr 2026 23:03:06 +0200 Subject: [PATCH] 2 - Add InstanceConfig value object and InstanceType enum --- .../src/Config/InstanceConfig.php | 65 ++++++++++ .../FediDiscover/src/Config/InstanceType.php | 10 ++ .../src/FediDiscoverServiceProvider.php | 6 +- .../tests/Unit/InstanceConfigTest.php | 121 ++++++++++++++++++ 4 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 packages/Lvl0/FediDiscover/src/Config/InstanceConfig.php create mode 100644 packages/Lvl0/FediDiscover/src/Config/InstanceType.php create mode 100644 packages/Lvl0/FediDiscover/tests/Unit/InstanceConfigTest.php diff --git a/packages/Lvl0/FediDiscover/src/Config/InstanceConfig.php b/packages/Lvl0/FediDiscover/src/Config/InstanceConfig.php new file mode 100644 index 0000000..b4576a4 --- /dev/null +++ b/packages/Lvl0/FediDiscover/src/Config/InstanceConfig.php @@ -0,0 +1,65 @@ + $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, + ]; + } +} diff --git a/packages/Lvl0/FediDiscover/src/Config/InstanceType.php b/packages/Lvl0/FediDiscover/src/Config/InstanceType.php new file mode 100644 index 0000000..fe70e64 --- /dev/null +++ b/packages/Lvl0/FediDiscover/src/Config/InstanceType.php @@ -0,0 +1,10 @@ +mergeConfigFrom(__DIR__.'/../config/fedi-discover.php', 'fedi-discover'); + $this->mergeConfigFrom(__DIR__ . '/../config/fedi-discover.php', 'fedi-discover'); } public function boot(): void { - $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); + $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); if ($this->app->runningInConsole()) { $this->publishes([ - __DIR__.'/../config/fedi-discover.php' => config_path('fedi-discover.php'), + __DIR__ . '/../config/fedi-discover.php' => config_path('fedi-discover.php'), ], 'fedi-discover-config'); } } diff --git a/packages/Lvl0/FediDiscover/tests/Unit/InstanceConfigTest.php b/packages/Lvl0/FediDiscover/tests/Unit/InstanceConfigTest.php new file mode 100644 index 0000000..03ffbf7 --- /dev/null +++ b/packages/Lvl0/FediDiscover/tests/Unit/InstanceConfigTest.php @@ -0,0 +1,121 @@ + '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()); + } +}