* Copyright 2005-2011, Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice * * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (https://cakefoundation.org) * @link https://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests * @since 1.2.0 * @license https://opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Test\TestCase\Controller; use Cake\Controller\Component\FlashComponent; use Cake\Controller\ComponentRegistry; use Cake\Controller\Controller; use Cake\Controller\Exception\MissingComponentException; use Cake\Core\Exception\CakeException; use Cake\Event\EventManager; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; use Exception; use TestApp\Controller\Component\AppleComponent; use TestApp\Controller\Component\BananaComponent; use TestApp\Controller\Component\ConfiguredComponent; use TestApp\Controller\Component\OrangeComponent; use TestApp\Controller\Component\SomethingWithFlashComponent; use TestApp\Controller\ComponentTestController; /** * ComponentTest class */ class ComponentTest extends TestCase { /** * setUp method */ public function setUp(): void { parent::setUp(); static::setAppNamespace(); } /** * test accessing inner components. */ public function testInnerComponentConstruction(): void { $Collection = new ComponentRegistry(new Controller(new ServerRequest())); $Component = new AppleComponent($Collection); $this->assertInstanceOf(OrangeComponent::class, $Component->Orange, 'class is wrong'); } /** * test component loading */ public function testNestedComponentLoading(): void { $Collection = new ComponentRegistry(new Controller(new ServerRequest())); $Apple = new AppleComponent($Collection); $this->assertInstanceOf(OrangeComponent::class, $Apple->Orange, 'class is wrong'); $this->assertInstanceOf(BananaComponent::class, $Apple->Orange->Banana, 'class is wrong'); $this->assertEmpty($Apple->Session); $this->assertEmpty($Apple->Orange->Session); } /** * test that component components are not enabled in the collection. */ public function testInnerComponentsAreNotEnabled(): void { $eventManager = new class extends EventManager { public bool $isCalled = false; public bool $isCorrectType = false; public function on($eventKey, $options = null, $callable = []): void { $this->isCalled = true; $this->isCorrectType = $eventKey instanceof AppleComponent; } }; $controller = new Controller(new ServerRequest()); $controller->setEventManager($eventManager); $Collection = new ComponentRegistry($controller); $Apple = $Collection->load('Apple'); $this->assertInstanceOf(OrangeComponent::class, $Apple->Orange, 'class is wrong'); $this->assertTrue($eventManager->isCalled, 'on() should be called'); $this->assertTrue($eventManager->isCorrectType, 'on() should be called with the correct type'); } /** * test a component being used more than once. */ public function testMultipleComponentInitialize(): void { $Collection = new ComponentRegistry(new Controller(new ServerRequest())); $Banana = $Collection->load('Banana'); $Orange = $Collection->load('Orange'); $this->assertSame($Banana, $Orange->Banana, 'Should be references'); $Banana->testField = 'OrangeField'; $this->assertSame($Banana->testField, $Orange->Banana->testField, 'References are broken'); } /** * Test a duplicate component being loaded more than once with same and differing configurations. */ public function testDuplicateComponentInitialize(): void { $this->expectException(CakeException::class); $this->expectExceptionMessage('The `Banana` alias has already been loaded. The `property` key'); $Collection = new ComponentRegistry(new Controller(new ServerRequest())); $Collection->load('Banana', ['property' => ['closure' => function (): void { }]]); $Collection->load('Banana', ['property' => ['closure' => function (): void { }]]); $this->assertInstanceOf(BananaComponent::class, $Collection->Banana, 'class is wrong'); $Collection->load('Banana', ['property' => ['differs']]); } /** * Test mutually referencing components. */ public function testSomethingReferencingFlashComponent(): void { $Controller = new ComponentTestController(new ServerRequest()); $Controller->loadComponent('SomethingWithFlash'); $Controller->startupProcess(); $this->assertInstanceOf(SomethingWithFlashComponent::class, $Controller->SomethingWithFlash); $this->assertInstanceOf(FlashComponent::class, $Controller->SomethingWithFlash->Flash); } /** * Tests __debugInfo */ public function testDebugInfo(): void { $Collection = new ComponentRegistry(new Controller(new ServerRequest())); $Component = new AppleComponent($Collection); $expected = [ 'components' => [ 'Orange' => [], ], 'implementedEvents' => [ 'Controller.startup' => 'startup', ], '_config' => [], ]; $result = $Component->__debugInfo(); $this->assertEquals($expected, $result); } /** * Tests null return for unknown magic properties. */ public function testMagicReturnsNull(): void { $Component = new AppleComponent(new ComponentRegistry(new Controller(new ServerRequest()))); $this->assertNull($Component->ShouldBeNull); } /** * Tests config via constructor */ public function testConfigViaConstructor(): void { $Component = new ConfiguredComponent( new ComponentRegistry(new Controller(new ServerRequest())), ['chicken' => 'soup'] ); $this->assertEquals(['chicken' => 'soup'], $Component->configCopy); $this->assertEquals(['chicken' => 'soup'], $Component->getConfig()); } /** * Lazy load a component without events. */ public function testLazyLoading(): void { $Component = new ConfiguredComponent( new ComponentRegistry(new Controller(new ServerRequest())), [], ['Apple', 'Banana', 'Orange'] ); $this->assertInstanceOf(AppleComponent::class, $Component->Apple, 'class is wrong'); $this->assertInstanceOf(OrangeComponent::class, $Component->Orange, 'class is wrong'); $this->assertInstanceOf(BananaComponent::class, $Component->Banana, 'class is wrong'); } /** * Lazy load a component that does not exist. */ public function testLazyLoadingDoesNotExists(): void { $this->expectException(MissingComponentException::class); $this->expectExceptionMessage('Component class `YouHaveNoBananasComponent` could not be found.'); $Component = new ConfiguredComponent(new ComponentRegistry(new Controller(new ServerRequest())), [], ['YouHaveNoBananas']); $Component->YouHaveNoBananas; } /** * Lazy loaded components can have config options */ public function testConfiguringInnerComponent(): void { $Component = new ConfiguredComponent( new ComponentRegistry(new Controller(new ServerRequest())), [], ['Configured' => ['foo' => 'bar']] ); $this->assertInstanceOf(ConfiguredComponent::class, $Component->Configured, 'class is wrong'); $this->assertNotSame($Component, $Component->Configured, 'Component instance was reused'); $this->assertEquals(['foo' => 'bar', 'enabled' => false], $Component->Configured->getConfig()); } /** * Test enabling events for lazy loaded components */ public function testEventsInnerComponent(): void { $eventManager = new class extends EventManager { public bool $isCalled = false; public bool $isCorrectType = false; public function on($eventKey, $options = null, $callable = []): void { $this->isCalled = true; $this->isCorrectType = $eventKey instanceof AppleComponent; } }; $controller = new Controller(new ServerRequest()); $controller->setEventManager($eventManager); $Collection = new ComponentRegistry($controller); $Component = new ConfiguredComponent($Collection, [], ['Apple' => ['enabled' => true]]); $this->assertInstanceOf(AppleComponent::class, $Component->Apple, 'class is wrong'); $this->assertTrue($eventManager->isCalled, 'on() should be called'); $this->assertTrue($eventManager->isCorrectType, 'on() should be called with the correct type'); } /** * Disabled events do not register for event listeners. */ public function testNoEventsInnerComponent(): void { $eventManager = new class extends EventManager { public function on($eventKey, $options = null, $callable = []): never { throw new Exception('Should not be called'); } }; $controller = new Controller(new ServerRequest()); $controller->setEventManager($eventManager); $Collection = new ComponentRegistry($controller); $Component = new ConfiguredComponent($Collection, [], ['Apple' => ['enabled' => false]]); $this->assertInstanceOf(AppleComponent::class, $Component->Apple, 'class is wrong'); } }