first commit

This commit is contained in:
2024-11-10 21:08:49 +01:00
commit 0d932ce5ee
14455 changed files with 2567501 additions and 0 deletions

View File

@@ -0,0 +1,324 @@
<?php
namespace Props;
class ContainerTest extends \PHPUnit_Framework_TestCase
{
const TEST_CLASS = 'Props\ContainerTestObject';
public function testBasicInterop()
{
$di = new Container();
$this->assertInstanceOf('Psr\Container\ContainerInterface', $di);
$this->assertFalse($di->has('foo'));
$di->foo = 'bar';
$this->assertTrue($di->has('foo'));
}
/**
* @expectedException \Props\NotFoundException
*/
public function testInteropNotFound()
{
$di = new Container();
$di->get('foo');
}
/**
* @expectedException \Psr\Container\ContainerExceptionInterface
*/
public function testInteropException1()
{
$di = new Container();
$di->setFactory('foo', null);
}
/**
* @expectedException \Psr\Container\ContainerExceptionInterface
*/
public function testInteropException2()
{
$di = new Container();
$di->setFactory('foo', function () {
throw new \Exception();
});
$di->foo;
}
public function testEmpty()
{
$di = new Container();
$this->assertFalse(isset($di->foo));
$this->assertFalse($di->has('foo'));
}
public function testValueSetRemovesFactory()
{
$di = new Container();
$di->foo = function () {
return 'Bar';
};
$di->foo = 'Foo';
$this->assertTrue(isset($di->foo));
$this->assertFalse($di->hasFactory('foo'));
}
public function testSetResolvable()
{
$di = new Container();
$di->foo = function () {
return new ContainerTestObject();
};
$this->assertTrue(isset($di->foo));
$this->assertTrue($di->has('foo'));
$this->assertTrue($di->hasFactory('foo'));
}
/**
* @expectedException \Props\NotFoundException
*/
public function testReadMissingValue()
{
$di = new Container();
$di->foo;
}
/**
* @expectedException \Props\NotFoundException
*/
public function testGetMissingValue()
{
$di = new Container();
$di->get('foo');
}
public function testGetNewUnresolvableValue()
{
$di = new Container();
$di->foo = 'Foo';
$this->setExpectedException('Props\NotFoundException');
$di->new_foo();
}
public function testSetAfterRead()
{
$di = new Container();
$di->foo = 'Foo';
$di->foo = 'Foo2';
$this->assertEquals('Foo2', $di->foo);
}
public function testHandlesNullValue()
{
$di = new Container();
$di->null = null;
$this->assertTrue(isset($di->null));
$this->assertTrue($di->has('null'));
$this->assertNull($di->null);
$this->assertNull($di->get('null'));
}
public function testFactoryReceivesContainer()
{
$di = new Container();
$di->foo = function () {
return func_get_args();
};
$foo = $di->foo;
$this->assertSame($foo[0], $di);
$this->assertEquals(count($foo), 1);
}
public function testGetResolvables()
{
$di = new Container();
$di->foo = function () {
return new ContainerTestObject();
};
$foo1 = $di->foo;
$foo2 = $di->foo;
$this->assertInstanceOf(self::TEST_CLASS, $foo1);
$this->assertSame($foo1, $foo2);
$foo3 = $di->new_foo();
$foo4 = $di->new_foo();
$this->assertInstanceOf(self::TEST_CLASS, $foo3);
$this->assertInstanceOf(self::TEST_CLASS, $foo4);
$this->assertNotSame($foo3, $foo4);
$this->assertNotSame($foo1, $foo3);
}
public function testKeyNamespace()
{
$di = new Container();
$di->foo = function () {
return new ContainerTestObject();
};
$di->new_foo = 'Foo';
$this->assertInstanceOf(self::TEST_CLASS, $di->new_foo());
$this->assertEquals('Foo', $di->new_foo);
}
public function testUnset()
{
$di = new Container();
$di->foo = 'Foo';
unset($di->foo);
$this->assertFalse(isset($di->foo));
}
public function testAccessUnsetValue()
{
$di = new Container();
$di->foo = 'Foo';
unset($di->foo);
$this->setExpectedException('Props\NotFoundException');
$di->foo;
}
public function testSetFactory()
{
$di = new Container();
$di->setFactory('foo', function () {
$obj = new ContainerTestObject();
$obj->bar = 'bar';
return $obj;
});
$foo = $di->foo;
$this->assertInstanceOf(self::TEST_CLASS, $foo);
$this->assertEquals('bar', $foo->bar);
}
public function testSetValue()
{
$di = new Container();
$di->setValue('foo', function () {});
$this->assertInstanceOf('Closure', $di->foo);
}
/**
* @expectedException \Props\NotFoundException
*/
public function testCannotExtendValue()
{
$di = new Container();
$di->foo = 1;
$di->extend('foo', function ($value, Container $c) {
return $value + 1;
});
}
public function testExtend()
{
$di = new Container();
$di->key = 'count';
$di->counter = function (Container $c) {
static $i = 0;
$i++;
return (object)array(
$c->key => $i,
);
};
$c1 = $di->counter; // cached with $i = 1
$di->extend('counter', function ($value, Container $c) {
static $i = 0;
$i++;
$value->one = $i;
return $value;
});
$c2 = $di->counter; // because of extension, doesn't use original cached value
$this->assertEquals((object)array('count' => 2, 'one' => 1), $c2);
$this->assertNotSame($c1, $c2);
$di->key = 'total';
$c3 = $di->counter; // but caches repeat reads
$this->assertEquals((object)array('count' => 2, 'one' => 1), $c3);
$this->assertSame($c2, $c3);
$c4 = $di->new_counter();
$this->assertEquals((object)array('total' => 3, 'one' => 2), $c4);
$this->assertNotSame($c3, $c4);
$di->extend('counter', function ($value, Container $c) {
static $i = 0;
$i++;
$value->two = $i;
return $value;
});
$c5 = $di->counter; // going deep!
$this->assertEquals((object)array('total' => 4, 'one' => 3, 'two' => 1), $c5);
$c6 = $di->new_counter();
$this->assertEquals((object)array('total' => 5, 'one' => 4, 'two' => 2), $c6);
}
/**
* @expectedException \Props\NotFoundException
*/
public function testGetFactoryForValue()
{
$di = new Container();
$di->key = 'count';
$di->getFactory('key');
}
/**
* @expectedException \Props\NotFoundException
*/
public function testGetMissingFactory()
{
$di = new Container();
$di->getFactory('key');
}
public function testGetFactory()
{
$di = new Container();
$factory = function () {};
$di->foo = $factory;
$factory2 = $di->getFactory('foo');
$this->assertSame($factory, $factory2);
}
public function testGetKeys()
{
$di = new Container();
$di->foo = 'foo';
$di->bar = function () {};
$di->bar;
$this->assertEquals(array('foo', 'bar'), $di->getKeys());
}
}
class ContainerTestObject
{
public $calls;
public $args;
public function __construct()
{
$this->args = func_get_args();
}
public function __call($name, $args)
{
$this->calls[$name] = $args[0];
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Props\Pimple\Tests;
class Invokable
{
public function __invoke($value = null)
{
$service = new Service();
$service->value = $value;
return $service;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Props\Pimple\Tests;
class NonInvokable
{
public function __call($a, $b)
{
}
}

View File

@@ -0,0 +1,452 @@
<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Props\Pimple\Tests;
use Props\Pimple;
/**
* Pimple Test
*
* @package pimple
* @author Igor Wiedler <igor@wiedler.ch>
*/
class PimpleTest extends \PHPUnit_Framework_TestCase
{
public function testWithString()
{
$pimple = new Pimple();
$pimple->param = 'value';
$this->assertEquals('value', $pimple->param);
}
public function testWithClosure()
{
$pimple = new Pimple();
$pimple->service = function () {
return new Service();
};
$this->assertInstanceOf('Props\Pimple\Tests\Service', $pimple->service);
}
public function testServicesShouldBeDifferent()
{
$pimple = new Pimple();
$pimple->service = $pimple->factory(function () {
return new Service();
});
$serviceOne = $pimple->service;
$this->assertInstanceOf('Props\Pimple\Tests\Service', $serviceOne);
$serviceTwo = $pimple->service;
$this->assertInstanceOf('Props\Pimple\Tests\Service', $serviceTwo);
$this->assertNotSame($serviceOne, $serviceTwo);
}
public function testShouldPassContainerAsParameter()
{
$pimple = new Pimple();
$pimple->service = function () {
return new Service();
};
$pimple->container = function ($container) {
return $container;
};
$this->assertNotSame($pimple, $pimple->service);
$this->assertSame($pimple, $pimple->container);
}
public function testIsset()
{
$pimple = new Pimple();
$pimple->param = 'value';
$pimple->service = function () {
return new Service();
};
$pimple->null = null;
$this->assertTrue(isset($pimple->param));
$this->assertTrue(isset($pimple->service));
$this->assertTrue(isset($pimple->null));
$this->assertFalse(isset($pimple->non_existent));
}
public function testConstructorInjection()
{
$params = array("param" => "value");
$pimple = new Pimple($params);
$this->assertSame($pimple->param, $pimple->param);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Identifier "foo" is not defined.
*/
public function testOffsetGetValidatesKeyIsPresent()
{
$pimple = new Pimple();
echo $pimple->foo;
}
public function testOffsetGetHonorsNullValues()
{
$pimple = new Pimple();
$pimple->foo = null;
$this->assertNull($pimple->foo);
}
public function testUnset()
{
$pimple = new Pimple();
$pimple->param = 'value';
$pimple->service = function () {
return new Service();
};
unset($pimple->param, $pimple->service);
$this->assertFalse(isset($pimple->param));
$this->assertFalse(isset($pimple->service));
}
/**
* @dataProvider serviceDefinitionProvider
*/
public function testShare($service)
{
$pimple = new Pimple();
$pimple->shared_service = $service;
$serviceOne = $pimple->shared_service;
$this->assertInstanceOf('Props\Pimple\Tests\Service', $serviceOne);
$serviceTwo = $pimple->shared_service;
$this->assertInstanceOf('Props\Pimple\Tests\Service', $serviceTwo);
$this->assertSame($serviceOne, $serviceTwo);
}
/**
* @dataProvider serviceDefinitionProvider
*/
public function testProtect($service)
{
$pimple = new Pimple();
$pimple->protected = $pimple->protect($service);
$this->assertSame($service, $pimple->protected);
}
public function testGlobalFunctionNameAsParameterValue()
{
$pimple = new Pimple();
$pimple->global_function = 'strlen';
$this->assertSame('strlen', $pimple->global_function);
}
public function testRaw()
{
$pimple = new Pimple();
$pimple->service = $definition = $pimple->factory(function () { return 'foo'; });
$this->assertSame($definition, $pimple->raw('service'));
}
public function testRawHonorsNullValues()
{
$pimple = new Pimple();
$pimple->foo = null;
$this->assertNull($pimple->raw('foo'));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Identifier "foo" is not defined.
*/
public function testRawValidatesKeyIsPresent()
{
$pimple = new Pimple();
$pimple->raw('foo');
}
/**
* @dataProvider serviceDefinitionProvider
*/
public function testExtend($service)
{
$pimple = new Pimple();
$pimple->shared_service = function () {
return new Service();
};
$pimple->factory_service = $pimple->factory(function () {
return new Service();
});
$pimple->extend('shared_service', $service);
$serviceOne = $pimple->shared_service;
$this->assertInstanceOf('Props\Pimple\Tests\Service', $serviceOne);
$serviceTwo = $pimple->shared_service;
$this->assertInstanceOf('Props\Pimple\Tests\Service', $serviceTwo);
$this->assertSame($serviceOne, $serviceTwo);
$this->assertSame($serviceOne->value, $serviceTwo->value);
$pimple->extend('factory_service', $service);
$serviceOne = $pimple->factory_service;
$this->assertInstanceOf('Props\Pimple\Tests\Service', $serviceOne);
$serviceTwo = $pimple->factory_service;
$this->assertInstanceOf('Props\Pimple\Tests\Service', $serviceTwo);
$this->assertNotSame($serviceOne, $serviceTwo);
$this->assertNotSame($serviceOne->value, $serviceTwo->value);
}
public function testExtendDoesNotLeakWithFactories()
{
$pimple = new Pimple();
$pimple->foo = $pimple->factory(function () { return; });
$pimple->foo = $pimple->extend('foo', function ($foo, $pimple) { return; });
unset($pimple->foo);
$class = new \ReflectionClass($pimple);
$class = $class->getParentClass();
$p = $class->getProperty('values');
$p->setAccessible(true);
$this->assertEmpty($p->getValue($pimple));
$p = $class->getProperty('factories');
$p->setAccessible(true);
$this->assertCount(0, $p->getValue($pimple));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Identifier "foo" is not defined.
*/
public function testExtendValidatesKeyIsPresent()
{
$pimple = new Pimple();
$pimple->extend('foo', function () {});
}
public function testKeys()
{
$pimple = new Pimple();
$pimple->foo = 123;
$pimple->bar = 123;
$this->assertEquals(array('foo', 'bar'), $pimple->keys());
}
/** @test */
public function settingAnInvokableObjectShouldTreatItAsFactory()
{
$pimple = new Pimple();
$pimple->invokable = new Invokable();
$this->assertInstanceOf('Props\Pimple\Tests\Service', $pimple->invokable);
}
/** @test */
public function settingNonInvokableObjectShouldTreatItAsParameter()
{
$pimple = new Pimple();
$pimple->non_invokable = new NonInvokable();
$this->assertInstanceOf('Props\Pimple\Tests\NonInvokable', $pimple->non_invokable);
}
/**
* @dataProvider badServiceDefinitionProvider
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Service definition is not a Closure or invokable object.
*/
public function testFactoryFailsForInvalidServiceDefinitions($service)
{
$pimple = new Pimple();
$pimple->factory($service);
}
/**
* @dataProvider badServiceDefinitionProvider
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Callable is not a Closure or invokable object.
*/
public function testProtectFailsForInvalidServiceDefinitions($service)
{
$pimple = new Pimple();
$pimple->protect($service);
}
/**
* @dataProvider badServiceDefinitionProvider
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Identifier "foo" does not contain an object definition.
*/
public function testExtendFailsForKeysNotContainingServiceDefinitions($service)
{
$pimple = new Pimple();
$pimple->foo = $service;
$pimple->extend('foo', function () {});
}
/**
* @dataProvider badServiceDefinitionProvider
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Extension service definition is not a Closure or invokable object.
*/
public function testExtendFailsForInvalidServiceDefinitions($service)
{
$pimple = new Pimple();
$pimple->foo = function () {};
$pimple->extend('foo', $service);
}
/**
* Provider for invalid service definitions
*/
public function badServiceDefinitionProvider()
{
return array(
array(123),
array(new NonInvokable())
);
}
/**
* Provider for service definitions
*/
public function serviceDefinitionProvider()
{
return array(
array(function ($value) {
$service = new Service();
$service->value = $value;
return $service;
}),
array(new Invokable())
);
}
public function testDefiningNewServiceAfterFreeze()
{
$pimple = new Pimple();
$pimple->foo = function () {
return 'foo';
};
$foo = $pimple->foo;
$pimple->bar = function () {
return 'bar';
};
$this->assertSame('bar', $pimple->bar);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Cannot override frozen service "foo".
*/
public function testOverridingServiceAfterFreeze()
{
$pimple = new Pimple();
$pimple->foo = function () {
return 'foo';
};
$foo = $pimple->foo;
$pimple->foo = function () {
return 'bar';
};
}
public function testRemovingServiceAfterFreeze()
{
$pimple = new Pimple();
$pimple->foo = function () {
return 'foo';
};
$foo = $pimple->foo;
unset($pimple->foo);
$pimple->foo = function () {
return 'bar';
};
$this->assertSame('bar', $pimple->foo);
}
public function testExtendingService()
{
$pimple = new Pimple();
$pimple->foo = function () {
return 'foo';
};
$pimple->foo = $pimple->extend('foo', function ($foo, $app) {
return "$foo.bar";
});
$pimple->foo = $pimple->extend('foo', function ($foo, $app) {
return "$foo.baz";
});
$this->assertSame('foo.bar.baz', $pimple->foo);
}
public function testExtendingServiceAfterOtherServiceFreeze()
{
$pimple = new Pimple();
$pimple->foo = function () {
return 'foo';
};
$pimple->bar = function () {
return 'bar';
};
$foo = $pimple->foo;
$pimple->bar = $pimple->extend('bar', function ($bar, $app) {
return "$bar.baz";
});
$this->assertSame('bar.baz', $pimple->bar);
}
public function testNoPrivateAccess()
{
$check = new AccessCheck();
$this->assertTrue(isset($check['values']));
$this->assertEquals('values', $check['values']);
}
}
class AccessCheck extends Pimple {
function __construct()
{
$this->values = 'values';
parent::__construct();
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Props\Pimple\Tests;
/**
* Pimple Test Service
*
* @package pimple
* @author Igor Wiedler <igor@wiedler.ch>
*/
class Service
{
public $value;
}