Completed
Push — master ( 211342...dcca72 )
by Michael
06:51
created

itThrowsExceptionForNonExistentRawOffset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 1
eloc 5
nc 1
nop 0
1
<?php
2
namespace Spec\Yapeal\Container;
3
4
use PhpSpec\Exception\Example\SkippingException;
5
use PhpSpec\ObjectBehavior;
6
use Spec\Yapeal\Invokable;
7
use Spec\Yapeal\MockService;
8
use Spec\Yapeal\NonInvokable;
9
10
/**
11
 * Class ContainerSpec
12
 *
13
 * @mixin \Yapeal\Container\Container
14
 *
15
 * @method void shouldBe($value)
16
 * @method void shouldContain($value)
17
 * @method void shouldImplement($interface)
18
 * @method void shouldHaveKey($key)
19
 * @method void shouldNotEqual($value)
20
 * @method void shouldReturn($result)
21
 *
22
 * @method void during($method, array $params)
23
 */
24
class ContainerSpec extends ObjectBehavior
25
{
26
    public function itIsInitializable()
27
    {
28
        $this->shouldHaveType('Yapeal\Container\Container');
29
    }
30
    public function itProvidedFluentInterfaceFromRegister($provider)
31
    {
32
        /**
33
         * @var \Yapeal\Container\ServiceProviderInterface $provider
34
         */
35
        $provider->beADoubleOf('\Yapeal\Container\ServiceProviderInterface');
36
        $provider->register($this)
37
            ->willReturn();
38
        $this->register($provider)
39
            ->shouldReturn($this);
40
    }
41
    public function itShouldAllowDefiningNewServiceAfterFreezingFirst()
42
    {
43
        $this['foo'] = function () {
44
            return 'fooValue';
45
        };
46
        $this['foo'];
47
        $this['bar'] = function () {
48
            return 'barValue';
49
        };
50
        $this['bar']->shouldReturn('barValue');
51
    }
52
    public function itShouldAllowExtendingNonFrozenService()
53
    {
54
        $this['foo'] = function () {
55
            return 'foo';
56
        };
57
        $this['foo'] = $this->extend('foo',
0 ignored issues
show
Bug introduced by
The method extend() does not exist on Spec\Yapeal\Container\ContainerSpec. Did you maybe mean itShouldAllowExtendingNonFrozenService()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
58
            function ($foo) {
59
                return "$foo.bar";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $foo instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
60
            });
61
        $this['foo'] = $this->extend('foo',
0 ignored issues
show
Bug introduced by
The method extend() does not exist on Spec\Yapeal\Container\ContainerSpec. Did you maybe mean itShouldAllowExtendingNonFrozenService()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
62
            function ($foo) {
63
                return "$foo.baz";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $foo instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
64
            });
65
        $this['foo']->shouldReturn('foo.bar.baz');
66
    }
67
    public function itShouldAllowExtendingOtherServiceAfterFreezingFirst()
68
    {
69
        $this['foo'] = function () {
70
            return 'foo';
71
        };
72
        $this['bar'] = function () {
73
            return 'bar';
74
        };
75
        $this['foo'];
76
        $this['bar'] = $this->extend('bar',
0 ignored issues
show
Bug introduced by
The method extend() does not exist on Spec\Yapeal\Container\ContainerSpec. Did you maybe mean itShouldAllowExtendingNonFrozenService()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
77
            function ($bar, $app) {
0 ignored issues
show
Unused Code introduced by
The parameter $app is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
78
                return "$bar.baz";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $bar instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
79
            });
80
        $this['bar']->shouldReturn('bar.baz');
81
    }
82
    public function itShouldAllowGlobalFunctionNamesAsParameterValue()
83
    {
84
        $globals = ['strlen', 'count', 'strtolower'];
85
        foreach ($globals as $global) {
86
            $this['global_function'] = $global;
87
            $this['global_function']->shouldReturn($global);
88
        }
89
    }
90
    public function itShouldAllowRemovingFrozenServiceAndThenSettingAgain()
91
    {
92
        $this['foo'] = function () {
93
            return 'fooValue';
94
        };
95
        $this['foo'];
96
        unset($this['foo']);
97
        $this['foo'] = function () {
98
            return 'barValue';
99
        };
100
    }
101
    public function itShouldAlsoUnsetKeyWhenUnsettingOffsets()
102
    {
103
        $this['param'] = 'value';
104
        $this['service'] = function () {
105
            return new MockService();
106
        };
107
        $this->keys()
108
            ->shouldHaveCount(2);
109
        unset($this['param'], $this['service']);
110
        $this->keys()
111
            ->shouldHaveCount(0);
112
    }
113
    public function itShouldHaveAnOffsetAfterOneIsSet()
114
    {
115
        $this->keys()
116
            ->shouldHaveCount(0);
117
        $this['param'] = 'value';
118
        $this->keys()
119
            ->shouldContain('param');
120
        $this->keys()
121
            ->shouldHaveCount(1);
122
    }
123
    public function itShouldHonorNullValuesInOffsetGet()
124
    {
125
        $this['foo'] = null;
126
        $this['foo']->shouldReturn(null);
127
    }
128
    public function itShouldHonorReturningNullValuesFromRaw()
129
    {
130
        $this['foo'] = null;
131
        $this->raw('foo')
132
            ->shouldReturn(null);
133
    }
134
    public function itShouldInitialiseOffsetsFromConstructor()
135
    {
136
        $params = ['param' => 'value', 'param2' => false];
137
        $this->beConstructedWith($params);
138
        $this->keys()
139
            ->shouldHaveCount(2);
140
        foreach ($params as $param => $value) {
141
            $this[$param]->shouldBe($value);
142
        }
143
    }
144
    public function itShouldNotInvokeProtectedServices()
145
    {
146
        $services = [
147
            function ($value) {
148
                $service = new MockService();
149
                $service->value = $value;
150
                return $service;
151
            },
152
            new Invokable()
153
        ];
154
        foreach ($services as $service) {
155
            $this['protected'] = $this->protect($service);
0 ignored issues
show
Bug introduced by
The method protect() does not exist on Spec\Yapeal\Container\ContainerSpec. Did you maybe mean itShouldNotInvokeProtectedServices()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
156
            $this['protected']->shouldReturn($service);
157
        }
158
    }
159
    public function itShouldPassContainerAsParameter()
160
    {
161
        $this['service'] = function () {
162
            return new MockService();
163
        };
164
        $this['container'] = function ($container) {
165
            return $container;
166
        };
167
        $this['service']->shouldNotEqual($this);
168
        $this['container']->shouldEqual($this);
169
    }
170
    public function itShouldReturnDifferentInstancesOfSameTypeFromFactory()
171
    {
172
        $this['service'] = $this->factory(function () {
0 ignored issues
show
Bug introduced by
The method factory() does not exist on Spec\Yapeal\Container\ContainerSpec. Did you maybe mean itShouldReturnDifferentI...OfSameTypeFromFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
173
            return new MockService();
174
        });
175
        $serviceOne = $this['service']->shouldHaveType('Spec\Yapeal\MockService');
176
        $this['service']->shouldNotEqual($serviceOne);
177
    }
178
    public function itShouldReturnOriginalInstanceFromRawWhenUsingFactory()
179
    {
180
        $definition = $this->factory(function () {
0 ignored issues
show
Bug introduced by
The method factory() does not exist on Spec\Yapeal\Container\ContainerSpec. Did you maybe mean itShouldReturnDifferentI...OfSameTypeFromFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
181
            return 'foo';
182
        });
183
        $this['service'] = $definition;
184
        $this->raw('service')
185
            ->shouldReturn($definition);
186
        $this['service']->shouldNotReturn($definition);
187
    }
188
    public function itShouldReturnSameInstanceAndTypeAsCallableReturns()
189
    {
190
        $this['service'] = function () {
191
            return new MockService();
192
        };
193
        $serviceOne = $this['service']->shouldHaveType('Spec\Yapeal\MockService');
194
        $this['service']->shouldEqual($serviceOne);
195
    }
196
    public function itShouldReturnSameTypeAndValueForSimpleValues()
197
    {
198
        foreach ([true, false, null, 'value', 1, 1.0, ['value']] as $item) {
199
            $this['param'] = $item;
200
            $this['param']->shouldBe($item);
201
        }
202
    }
203
    public function itShouldReturnTrueFromOffsetExistsForAnySetKey()
204
    {
205
        $this['param'] = 'value';
206
        $this['service'] = function () {
207
            return new MockService();
208
        };
209
        $this['null'] = null;
210
        $this->offsetExists('param')
211
            ->shouldReturn(true);
212
        $this->offsetExists('param')
213
            ->shouldReturn(isset($this['param']));
214
        $this->offsetExists('service')
215
            ->shouldReturn(true);
216
        $this->offsetExists('service')
217
            ->shouldReturn(isset($this['service']));
218
        $this->offsetExists('null')
219
            ->shouldReturn(true);
220
        $this->offsetExists('null')
221
            ->shouldReturn(isset($this['null']));
222
        $this->offsetExists('non_existent')
223
            ->shouldNotReturn(true);
224
        $this->offsetExists('non_existent')
225
            ->shouldNotReturn(isset($this['non_existent']));
226
    }
227
    public function itShouldTreatInvokableObjectLikeCallable()
228
    {
229
        $this['invokable'] = new Invokable();
230
        $invoked = $this['invokable']->shouldHaveType('Spec\Yapeal\MockService');
231
        $this['invokable']->shouldReturn($invoked);
232
    }
233
    public function itShouldTreatNonInvokableObjectLikeParameter()
234
    {
235
        $this['non_invokable'] = new NonInvokable();
236
        $this['non_invokable']->shouldHaveType('Spec\Yapeal\NonInvokable');
237
    }
238
    public function itThrowsExceptionForNonExistentExtendOffset()
239
    {
240
        $id = 'param';
241
        $mess = sprintf('Identifier "%s" is not defined.', $id);
242
        $this->shouldThrow(new \InvalidArgumentException($mess))
243
            ->during('extend',
244
                [
245
                    $id,
246
                    function () {
247
                    }
248
                ]);
249
    }
250
    public function itThrowsExceptionForNonExistentGetOffset()
251
    {
252
        $id = 'param';
253
        $mess = sprintf('Identifier "%s" is not defined.', $id);
254
        $this->shouldThrow(new \InvalidArgumentException($mess))
255
            ->during('offsetGet', [$id]);
256
    }
257
    public function itThrowsExceptionForNonExistentRawOffset()
258
    {
259
        $id = 'param';
260
        $mess = sprintf('Identifier "%s" is not defined.', $id);
261
        $this->shouldThrow(new \InvalidArgumentException($mess))
262
            ->during('raw', [$id]);
263
    }
264
    public function itThrowsExceptionWhenExtendIsGivenNonInvokable()
265
    {
266
        if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
267
            throw new SkippingException('Unneeded on PHP 7.x or higher caught by TypeError');
268
        }
269
        $this['foo'] = function () {
270
            return 'foo';
271
        };
272
        $this->shouldThrow(new \InvalidArgumentException('Extension service definition is not a Closure or invokable object.'))
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 127 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
273
            ->during('extend', ['foo', new NonInvokable()]);
274
    }
275
    public function itThrowsExceptionWhenFactoryIsGivenNonInvokable()
276
    {
277
        if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
278
            throw new SkippingException('Unneeded on PHP 7.x or higher caught by TypeError');
279
        }
280
        $this['service'] = $this->shouldThrow(new \InvalidArgumentException('Service definition is not a Closure or invokable object.'))
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 136 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
281
            ->during('factory', [123]);
282
        $this['service'] = $this->shouldThrow(new \InvalidArgumentException('Service definition is not a Closure or invokable object.'))
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 136 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
283
            ->during('factory', [new NonInvokable()]);
284
    }
285
    public function itThrowsExceptionWhenProtectIsGivenNonInvokable()
286
    {
287
        if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
288
            throw new SkippingException('Unneeded on PHP 7.x or higher caught by TypeError');
289
        }
290
        $this->shouldThrow(new \InvalidArgumentException('Callable is not a Closure or invokable object.'))
291
            ->during('protect', [new NonInvokable()]);
292
    }
293
    public function itThrowsExceptionWhenTryingToExtendNonInvokable()
294
    {
295
        $this['param'] = 123;
296
        $this['non_invokable'] = new NonInvokable();
297
        $this['param'] = $this->shouldThrow(new \InvalidArgumentException('Identifier "param" does not contain an object definition.'))
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 135 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
298
            ->during('extend',
299
                [
300
                    'param',
301
                    function () {
302
                    }
303
                ]);
304
        $this['non_invokable'] = $this->shouldThrow(new \InvalidArgumentException('Identifier "non_invokable" does not contain an object definition.'))
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 151 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
305
            ->during('extend',
306
                [
307
                    'non_invokable',
308
                    function () {
309
                    }
310
                ]);
311
    }
312
    public function itThrowsExceptionWhenTryingToExtendingFrozenService()
313
    {
314
        $this['foo'] = function () {
315
            return 'foo';
316
        };
317
        $this['foo'] = $this->extend('foo',
0 ignored issues
show
Bug introduced by
The method extend() does not exist on Spec\Yapeal\Container\ContainerSpec. Did you maybe mean itShouldAllowExtendingNonFrozenService()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
318
            function ($foo) {
319
                return "$foo.bar";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $foo instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
320
            });
321
        $this['foo']->shouldReturn('foo.bar');
322
        $this->shouldThrow(new \InvalidArgumentException('Identifier "foo" does not contain an object definition.'))
323
            ->during('extend',
324
                [
325
                    'foo',
326
                    function ($foo) {
327
                        return "$foo.baz";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $foo instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
328
                    }
329
                ]);
330
    }
331
    public function itThrowsExceptionWhenTryingToGetOffsetAfterTheyHaveBeenUnset()
332
    {
333
        $this['param'] = 'value';
334
        $this['service'] = function () {
335
            return new MockService();
336
        };
337
        $this->keys()
338
            ->shouldHaveCount(2);
339
        unset($this['param'], $this['service']);
340
        $this->shouldThrow(new \InvalidArgumentException('Identifier "param" is not defined.'))
341
            ->during('offsetGet', ['param']);
342
        $this->shouldThrow(new \InvalidArgumentException('Identifier "service" is not defined.'))
343
            ->during('offsetGet', ['service']);
344
    }
345
    public function itThrowsExceptionWhenTryingToOverWriteFrozenService()
346
    {
347
        $this['foo'] = function () {
348
            return 'foo';
349
        };
350
        $this['foo'];
351
        $this->shouldThrow(new \RuntimeException('Cannot override frozen service "foo".'))
352
            ->during('offsetSet',
353
                [
354
                    'foo',
355
                    function () {
356
                        return 'bar';
357
                    }
358
                ]);
359
    }
360
}
361