315 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
		
		
			
		
	
	
			315 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
|  | <?php | ||
|  | 
 | ||
|  | namespace think\tests; | ||
|  | 
 | ||
|  | use PHPUnit\Framework\TestCase; | ||
|  | use ReflectionMethod; | ||
|  | use stdClass; | ||
|  | use think\Container; | ||
|  | use think\exception\ClassNotFoundException; | ||
|  | use think\exception\FuncNotFoundException; | ||
|  | 
 | ||
|  | class Taylor | ||
|  | { | ||
|  |     public $name; | ||
|  | 
 | ||
|  |     public function __construct($name) | ||
|  |     { | ||
|  |         $this->name = $name; | ||
|  |     } | ||
|  | 
 | ||
|  |     public function some(Container $container) | ||
|  |     { | ||
|  |     } | ||
|  | 
 | ||
|  |     protected function protectionFun() | ||
|  |     { | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  |     public static function test(Container $container) | ||
|  |     { | ||
|  |         return $container; | ||
|  |     } | ||
|  | 
 | ||
|  |     public static function __make() | ||
|  |     { | ||
|  |         return new self('Taylor'); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | class SomeClass | ||
|  | { | ||
|  |     public $container; | ||
|  | 
 | ||
|  |     public $count = 0; | ||
|  | 
 | ||
|  |     public function __construct(Container $container) | ||
|  |     { | ||
|  |         $this->container = $container; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | class ContainerTest extends TestCase | ||
|  | { | ||
|  |     protected function tearDown(): void | ||
|  |     { | ||
|  |         Container::setInstance(null); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testClosureResolution() | ||
|  |     { | ||
|  |         $container = new Container; | ||
|  | 
 | ||
|  |         Container::setInstance($container); | ||
|  | 
 | ||
|  |         $container->bind('name', function () { | ||
|  |             return 'Taylor'; | ||
|  |         }); | ||
|  | 
 | ||
|  |         $this->assertEquals('Taylor', $container->make('name')); | ||
|  | 
 | ||
|  |         $this->assertEquals('Taylor', Container::pull('name')); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testGet() | ||
|  |     { | ||
|  |         $container = new Container; | ||
|  | 
 | ||
|  |         $this->expectException(ClassNotFoundException::class); | ||
|  |         $this->expectExceptionMessage('class not exists: name'); | ||
|  |         $container->get('name'); | ||
|  | 
 | ||
|  |         $container->bind('name', function () { | ||
|  |             return 'Taylor'; | ||
|  |         }); | ||
|  | 
 | ||
|  |         $this->assertSame('Taylor', $container->get('name')); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testExist() | ||
|  |     { | ||
|  |         $container = new Container; | ||
|  | 
 | ||
|  |         $container->bind('name', function () { | ||
|  |             return 'Taylor'; | ||
|  |         }); | ||
|  | 
 | ||
|  |         $this->assertFalse($container->exists("name")); | ||
|  | 
 | ||
|  |         $container->make('name'); | ||
|  | 
 | ||
|  |         $this->assertTrue($container->exists('name')); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testInstance() | ||
|  |     { | ||
|  |         $container = new Container; | ||
|  | 
 | ||
|  |         $container->bind('name', function () { | ||
|  |             return 'Taylor'; | ||
|  |         }); | ||
|  | 
 | ||
|  |         $this->assertEquals('Taylor', $container->get('name')); | ||
|  | 
 | ||
|  |         $container->bind('name2', Taylor::class); | ||
|  | 
 | ||
|  |         $object = new stdClass(); | ||
|  | 
 | ||
|  |         $this->assertFalse($container->exists('name2')); | ||
|  | 
 | ||
|  |         $container->instance('name2', $object); | ||
|  | 
 | ||
|  |         $this->assertTrue($container->exists('name2')); | ||
|  | 
 | ||
|  |         $this->assertTrue($container->exists(Taylor::class)); | ||
|  | 
 | ||
|  |         $this->assertEquals($object, $container->make(Taylor::class)); | ||
|  | 
 | ||
|  |         unset($container->name1); | ||
|  | 
 | ||
|  |         $this->assertFalse($container->exists('name1')); | ||
|  | 
 | ||
|  |         $container->delete('name2'); | ||
|  | 
 | ||
|  |         $this->assertFalse($container->exists('name2')); | ||
|  | 
 | ||
|  |         foreach ($container as $class => $instance) { | ||
|  | 
 | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testBind() | ||
|  |     { | ||
|  |         $container = new Container; | ||
|  | 
 | ||
|  |         $object = new stdClass(); | ||
|  | 
 | ||
|  |         $container->bind(['name' => Taylor::class]); | ||
|  | 
 | ||
|  |         $container->bind('name2', $object); | ||
|  | 
 | ||
|  |         $container->bind('name3', Taylor::class); | ||
|  |         $container->bind('name3', Taylor::class); | ||
|  | 
 | ||
|  |         $container->name4 = $object; | ||
|  | 
 | ||
|  |         $container['name5'] = $object; | ||
|  | 
 | ||
|  |         $this->assertTrue(isset($container->name4)); | ||
|  | 
 | ||
|  |         $this->assertTrue(isset($container['name5'])); | ||
|  | 
 | ||
|  |         $this->assertInstanceOf(Taylor::class, $container->get('name')); | ||
|  | 
 | ||
|  |         $this->assertSame($object, $container->get('name2')); | ||
|  | 
 | ||
|  |         $this->assertSame($object, $container->name4); | ||
|  | 
 | ||
|  |         $this->assertSame($object, $container['name5']); | ||
|  | 
 | ||
|  |         $this->assertInstanceOf(Taylor::class, $container->get('name3')); | ||
|  | 
 | ||
|  |         unset($container['name']); | ||
|  | 
 | ||
|  |         $this->assertFalse(isset($container['name'])); | ||
|  | 
 | ||
|  |         unset($container->name3); | ||
|  | 
 | ||
|  |         $this->assertFalse(isset($container->name3)); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testAutoConcreteResolution() | ||
|  |     { | ||
|  |         $container = new Container; | ||
|  | 
 | ||
|  |         $taylor = $container->make(Taylor::class); | ||
|  | 
 | ||
|  |         $this->assertInstanceOf(Taylor::class, $taylor); | ||
|  |         $this->assertAttributeSame('Taylor', 'name', $taylor); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testGetAndSetInstance() | ||
|  |     { | ||
|  |         $this->assertInstanceOf(Container::class, Container::getInstance()); | ||
|  | 
 | ||
|  |         $object = new stdClass(); | ||
|  | 
 | ||
|  |         Container::setInstance($object); | ||
|  | 
 | ||
|  |         $this->assertSame($object, Container::getInstance()); | ||
|  | 
 | ||
|  |         Container::setInstance(function () { | ||
|  |             return $this; | ||
|  |         }); | ||
|  | 
 | ||
|  |         $this->assertSame($this, Container::getInstance()); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testResolving() | ||
|  |     { | ||
|  |         $container = new Container(); | ||
|  |         $container->bind(Container::class, $container); | ||
|  | 
 | ||
|  |         $container->resolving(function (SomeClass $taylor, Container $container) { | ||
|  |             $taylor->count++; | ||
|  |         }); | ||
|  |         $container->resolving(SomeClass::class, function (SomeClass $taylor, Container $container) { | ||
|  |             $taylor->count++; | ||
|  |         }); | ||
|  | 
 | ||
|  |         /** @var SomeClass $someClass */ | ||
|  |         $someClass = $container->invokeClass(SomeClass::class); | ||
|  |         $this->assertEquals(2, $someClass->count); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testInvokeFunctionWithoutMethodThrowsException() | ||
|  |     { | ||
|  |         $this->expectException(FuncNotFoundException::class); | ||
|  |         $this->expectExceptionMessage('function not exists: ContainerTestCallStub()'); | ||
|  |         $container = new Container(); | ||
|  |         $container->invokeFunction('ContainerTestCallStub', []); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testInvokeProtectionMethod() | ||
|  |     { | ||
|  |         $container = new Container(); | ||
|  |         $this->assertTrue($container->invokeMethod([Taylor::class, 'protectionFun'], [], true)); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testInvoke() | ||
|  |     { | ||
|  |         $container = new Container(); | ||
|  | 
 | ||
|  |         Container::setInstance($container); | ||
|  | 
 | ||
|  |         $container->bind(Container::class, $container); | ||
|  | 
 | ||
|  |         $stub = $this->createMock(Taylor::class); | ||
|  | 
 | ||
|  |         $stub->expects($this->once())->method('some')->with($container)->will($this->returnSelf()); | ||
|  | 
 | ||
|  |         $container->invokeMethod([$stub, 'some']); | ||
|  | 
 | ||
|  |         $this->assertEquals('48', $container->invoke('ord', ['0'])); | ||
|  | 
 | ||
|  |         $this->assertSame($container, $container->invoke(Taylor::class . '::test', [])); | ||
|  | 
 | ||
|  |         $this->assertSame($container, $container->invokeMethod(Taylor::class . '::test')); | ||
|  | 
 | ||
|  |         $reflect = new ReflectionMethod($container, 'exists'); | ||
|  | 
 | ||
|  |         $this->assertTrue($container->invokeReflectMethod($container, $reflect, [Container::class])); | ||
|  | 
 | ||
|  |         $this->assertSame($container, $container->invoke(function (Container $container) { | ||
|  |             return $container; | ||
|  |         })); | ||
|  | 
 | ||
|  |         $this->assertSame($container, $container->invoke(Taylor::class . '::test')); | ||
|  | 
 | ||
|  |         $object = $container->invokeClass(SomeClass::class); | ||
|  |         $this->assertInstanceOf(SomeClass::class, $object); | ||
|  |         $this->assertSame($container, $object->container); | ||
|  | 
 | ||
|  |         $stdClass = new stdClass(); | ||
|  | 
 | ||
|  |         $container->invoke(function (Container $container, stdClass $stdObject, $key1, $lowKey, $key2 = 'default') use ($stdClass) { | ||
|  |             $this->assertEquals('value1', $key1); | ||
|  |             $this->assertEquals('default', $key2); | ||
|  |             $this->assertEquals('value2', $lowKey); | ||
|  |             $this->assertSame($stdClass, $stdObject); | ||
|  |             return $container; | ||
|  |         }, ['some' => $stdClass, 'key1' => 'value1', 'low_key' => 'value2']); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testInvokeMethodNotExists() | ||
|  |     { | ||
|  |         $container = $this->resolveContainer(); | ||
|  |         $this->expectException(FuncNotFoundException::class); | ||
|  | 
 | ||
|  |         $container->invokeMethod([SomeClass::class, 'any']); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function testInvokeClassNotExists() | ||
|  |     { | ||
|  |         $container = new Container(); | ||
|  | 
 | ||
|  |         Container::setInstance($container); | ||
|  | 
 | ||
|  |         $container->bind(Container::class, $container); | ||
|  | 
 | ||
|  |         $this->expectExceptionObject(new ClassNotFoundException('class not exists: SomeClass')); | ||
|  | 
 | ||
|  |         $container->invokeClass('SomeClass'); | ||
|  |     } | ||
|  | 
 | ||
|  |     protected function resolveContainer() | ||
|  |     { | ||
|  |         $container = new Container(); | ||
|  | 
 | ||
|  |         Container::setInstance($container); | ||
|  |         return $container; | ||
|  |     } | ||
|  | 
 | ||
|  | } |