|
29 | 29 | use function call_user_func_array;
|
30 | 30 | use function restore_error_handler;
|
31 | 31 | use function set_error_handler;
|
| 32 | +use ZendTest\ServiceManager\TestAsset\SampleFactory; |
32 | 33 |
|
33 | 34 | trait CommonServiceLocatorBehaviorsTrait
|
34 | 35 | {
|
@@ -879,4 +880,128 @@ public function testCoverageDepthFirstTaggingOnRecursiveAliasDefinitions()
|
879 | 880 | $this->assertSame($sm->get('alias1'), $sm->get('alias2'));
|
880 | 881 | $this->assertSame($sm->get(stdClass::class), $sm->get('alias1'));
|
881 | 882 | }
|
| 883 | + |
| 884 | + /** |
| 885 | + * The particular test procedure called by |
| 886 | + * testConsistencyOverInternalStates |
| 887 | + * |
| 888 | + * This test calls build()/get() and in between has() 3 times for |
| 889 | + * the given service name. |
| 890 | + * It asserts that sm continues to have (has) a service, asserts |
| 891 | + * that the built services each reference an object different |
| 892 | + * from all other objects, and asserts that the services got |
| 893 | + * reference the same object. |
| 894 | + * |
| 895 | + * @see testConsistencyOverInternalStates |
| 896 | + * |
| 897 | + * @param ContainerInterface $smTemplate |
| 898 | + * @param string $name |
| 899 | + * @param array[] string $test |
| 900 | + */ |
| 901 | + protected function checkConsistencyOverInternalStates($smTemplate, $name, $test) |
| 902 | + { |
| 903 | + $sm = clone $smTemplate; |
| 904 | + $object['get'] = []; |
| 905 | + $object['build'] = []; |
| 906 | + |
| 907 | + // call get()/build() and store the retrieved |
| 908 | + // objects in $object['get'] or $object['build'] |
| 909 | + // respectively |
| 910 | + foreach ($test as $method) { |
| 911 | + $object[$method][] = $sm->$method($name); |
| 912 | + $this->assertTrue($sm->has($name)); |
| 913 | + } |
| 914 | + |
| 915 | + // if there is more than one object in $object['get'] |
| 916 | + // compare all to the first |
| 917 | + $nrShared = count($object['get']); |
| 918 | + for ($i = 1; $i < $nrShared; $i++) { |
| 919 | + $this->assertSame($object['get'][0], $object['get'][$i]); |
| 920 | + } |
| 921 | + // objects from object['build'] have to be different |
| 922 | + // from all other objects |
| 923 | + foreach ($object['build'] as $idx1 => $nonSharedObj) { |
| 924 | + foreach ($object['get'] as $sharedObj) { |
| 925 | + $this->assertNotSame($nonSharedObj, $sharedObj); |
| 926 | + } |
| 927 | + foreach ($object['build'] as $idx2 => $nonSharedObj2) { |
| 928 | + if ($idx1 !== $idx2) { |
| 929 | + $this->assertNotSame($nonSharedObj, $nonSharedObj2); |
| 930 | + } |
| 931 | + } |
| 932 | + } |
| 933 | + } |
| 934 | + |
| 935 | + /** |
| 936 | + * The ServiceManager can change internal state on calls to get, |
| 937 | + * build or has, latter not currently. Possible state changes |
| 938 | + * are caching a factory, registering a service produced by |
| 939 | + * a factory, ... |
| 940 | + * |
| 941 | + * This tests performs three consecutive calls to build/get for |
| 942 | + * each registered service to push the service manager through |
| 943 | + * all internal states, thereby verifying that build/get/has |
| 944 | + * remain stable through the internal states. |
| 945 | + * |
| 946 | + * @see testConsistencyOverInternalStates below |
| 947 | + * |
| 948 | + * @param ContainerInterface $smTemplate |
| 949 | + * @param string $name |
| 950 | + * @param array[] string $test |
| 951 | + */ |
| 952 | + public function testConsistencyOverInternalStates() |
| 953 | + { |
| 954 | + $config = [ |
| 955 | + 'factories' => [ |
| 956 | + 'factory' => SampleFactory::class, |
| 957 | + 'service' => function ($container, $requestedName, array $options = null) { |
| 958 | + return new stdClass(); |
| 959 | + }, |
| 960 | + ], |
| 961 | + 'invokables' => [ |
| 962 | + 'invokable' => InvokableObject::class, |
| 963 | + ], |
| 964 | + 'services' => [ |
| 965 | + 'service' => new stdClass(), |
| 966 | + ], |
| 967 | + 'aliases' => [ |
| 968 | + 'serviceAlias' => 'service', |
| 969 | + 'invokableAlias' => 'invokable', |
| 970 | + 'factoryAlias' => 'factory', |
| 971 | + 'abstractFactoryAlias' => stdClass::class |
| 972 | + ], |
| 973 | + 'abstract_factories' => [ |
| 974 | + SimpleAbstractFactory::class, |
| 975 | + ] |
| 976 | + ]; |
| 977 | + |
| 978 | + $smTemplate = $this->createContainer($config); |
| 979 | + |
| 980 | + // produce all 3-tuples of 'build' and 'get' |
| 981 | + $methods = ['get', 'build']; |
| 982 | + foreach ($methods as $method1) { |
| 983 | + foreach ($methods as $method2) { |
| 984 | + foreach ($methods as $method3) { |
| 985 | + $tests[] = [$method1, $method2, $method3]; |
| 986 | + } |
| 987 | + } |
| 988 | + } |
| 989 | + |
| 990 | + // To allow changes to the config above |
| 991 | + // $names is not hard coded |
| 992 | + $names = array_merge( |
| 993 | + $config['factories'], |
| 994 | + $config['invokables'], |
| 995 | + $config['services'], |
| 996 | + $config['aliases'] |
| 997 | + ); |
| 998 | + $names[stdClass::class] = true; |
| 999 | + |
| 1000 | + foreach ($names as $name => $_) { |
| 1001 | + foreach ($tests as $test) { |
| 1002 | + $sm = clone $smTemplate; |
| 1003 | + $this->checkConsistencyOverInternalStates($smTemplate, $name, $test); |
| 1004 | + } |
| 1005 | + } |
| 1006 | + } |
882 | 1007 | }
|
0 commit comments