* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved. * @license GNU General Public License version 3 or later; see LICENSE * SPDX-License-Identifier: GPL-3.0-or-later */ namespace MokoSuiteCross\Tests\Unit\Service; use Joomla\Component\MokoSuiteCross\Administrator\Service\MokoSuiteCrossServiceInterface; use PHPUnit\Framework\TestCase; class ServiceInterfaceContractTest extends TestCase { public function testInterfaceExists(): void { $this->assertTrue(interface_exists(MokoSuiteCrossServiceInterface::class)); } public function testInterfaceDefinesRequiredMethods(): void { $reflection = new \ReflectionClass(MokoSuiteCrossServiceInterface::class); $expectedMethods = [ 'getServiceType', 'getServiceName', 'publish', 'validateCredentials', 'getMaxLength', 'supportsMedia', 'getSupportedMediaTypes', ]; foreach ($expectedMethods as $method) { $this->assertTrue( $reflection->hasMethod($method), "Interface missing method: {$method}" ); } } public function testGetServiceTypeReturnsString(): void { $method = new \ReflectionMethod(MokoSuiteCrossServiceInterface::class, 'getServiceType'); $returnType = $method->getReturnType(); $this->assertNotNull($returnType); $this->assertSame('string', $returnType->getName()); } public function testPublishAcceptsCorrectParameters(): void { $method = new \ReflectionMethod(MokoSuiteCrossServiceInterface::class, 'publish'); $params = $method->getParameters(); $this->assertCount(4, $params); $this->assertSame('message', $params[0]->getName()); $this->assertSame('media', $params[1]->getName()); $this->assertSame('credentials', $params[2]->getName()); $this->assertSame('params', $params[3]->getName()); } public function testPublishReturnsArray(): void { $method = new \ReflectionMethod(MokoSuiteCrossServiceInterface::class, 'publish'); $returnType = $method->getReturnType(); $this->assertNotNull($returnType); $this->assertSame('array', $returnType->getName()); } public function testGetMaxLengthReturnsInt(): void { $method = new \ReflectionMethod(MokoSuiteCrossServiceInterface::class, 'getMaxLength'); $returnType = $method->getReturnType(); $this->assertNotNull($returnType); $this->assertSame('int', $returnType->getName()); } public function testSupportsMediaReturnsBool(): void { $method = new \ReflectionMethod(MokoSuiteCrossServiceInterface::class, 'supportsMedia'); $returnType = $method->getReturnType(); $this->assertNotNull($returnType); $this->assertSame('bool', $returnType->getName()); } /** * @dataProvider servicePluginClassProvider */ public function testServicePluginImplementsInterface(string $className): void { if (!class_exists($className)) { $this->markTestSkipped("Class {$className} not autoloadable (needs Joomla runtime)"); } $this->assertTrue( is_subclass_of($className, MokoSuiteCrossServiceInterface::class), "{$className} does not implement MokoSuiteCrossServiceInterface" ); } public static function servicePluginClassProvider(): array { $plugins = [ 'facebook', 'twitter', 'linkedin', 'mastodon', 'bluesky', 'telegram', 'discord', 'slack', 'mailchimp', 'medium', 'instagram', 'youtube', 'threads', 'pinterest', 'reddit', ]; $cases = []; foreach ($plugins as $plugin) { $class = ucfirst($plugin); $cases[$plugin] = [ "Joomla\\Plugin\\MokoSuiteCross\\{$class}\\Extension\\{$class}Service", ]; } return $cases; } }