Completed
Push — master ( a54f79...70dbe9 )
by Bernhard
02:34
created

testAddBindingAcceptsDuplicates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 9

Duplication

Lines 14
Ratio 66.67 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 14
loc 21
ccs 10
cts 10
cp 1
rs 9.3142
cc 1
eloc 9
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the puli/discovery package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Puli\Discovery\Test;
13
14
use Puli\Discovery\Api\Binding\Binding;
15
use Puli\Discovery\Api\Binding\Initializer\BindingInitializer;
16
use Puli\Discovery\Api\Discovery;
17
use Puli\Discovery\Api\EditableDiscovery;
18
use Puli\Discovery\Api\Type\BindingParameter;
19
use Puli\Discovery\Api\Type\BindingType;
20
use Puli\Discovery\Test\Fixtures\Bar;
21
use Puli\Discovery\Test\Fixtures\Foo;
22
use Puli\Discovery\Test\Fixtures\StringBinding;
23
use stdClass;
24
use Webmozart\Expression\Expr;
25
26
/**
27
 * @since  1.0
28
 *
29
 * @author Bernhard Schussek <[email protected]>
30
 */
31
abstract class AbstractEditableDiscoveryTest extends AbstractDiscoveryTest
32
{
33
    /**
34
     * Creates a discovery that can be written in the test.
35
     *
36
     * @param BindingInitializer[] $initializers
37
     *
38
     * @return EditableDiscovery
39
     */
40
    abstract protected function createDiscovery(array $initializers = array());
41
42
    /**
43
     * Creates a discovery that can be read in the test.
44
     *
45
     * This method is needed to test whether the discovery actually synchronized
46
     * all in-memory changes to the backing data store:
47
     *
48
     *  * If the method returns the passed $discovery, the in-memory data
49
     *    structures are tested.
50
     *  * If the method returns a new discovery with the same backing data store,
51
     *    that data store is tested.
52
     *
53
     * @param EditableDiscovery    $discovery
54
     * @param BindingInitializer[] $initializers
55
     *
56
     * @return EditableDiscovery
57
     */
58
    abstract protected function loadDiscoveryFromStorage(EditableDiscovery $discovery, array $initializers = array());
59
60
    /**
61
     * @param BindingType[]        $types
62
     * @param Binding[]            $bindings
63
     * @param BindingInitializer[] $initializers
64
     *
65
     * @return Discovery
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use EditableDiscovery.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
66
     */
67 100
    protected function createLoadedDiscovery(array $types = array(), array $bindings = array(), array $initializers = array())
68
    {
69 100
        $discovery = $this->createDiscovery($initializers);
70
71 100
        foreach ($types as $type) {
72 50
            $discovery->addBindingType($type);
73
        }
74
75 100
        foreach ($bindings as $binding) {
76 30
            $discovery->addBinding($binding);
77
        }
78
79 100
        return $this->loadDiscoveryFromStorage($discovery);
80
    }
81
82 5 View Code Duplication
    public function testAddBinding()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
83
    {
84 5
        $binding = new StringBinding('string', Foo::clazz);
85
86 5
        $discovery = $this->createDiscovery();
87 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
88 5
        $discovery->addBinding($binding);
89
90 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
91
92 5
        $this->assertCount(1, $discovery->findBindings(Foo::clazz));
93 5
        $this->assertCount(1, $discovery->getBindings());
94 5
    }
95
96
    /**
97
     * @expectedException \Puli\Discovery\Api\Type\NoSuchTypeException
98
     * @expectedExceptionMessage Foo
99
     */
100 5
    public function testAddBindingFailsIfTypeNotFound()
101
    {
102 5
        $discovery = $this->createDiscovery();
103 5
        $discovery->addBinding(new StringBinding('string', Foo::clazz));
104
    }
105
106
    /**
107
     * @expectedException \Puli\Discovery\Api\Type\BindingNotAcceptedException
108
     * @expectedExceptionMessage Foo
109
     */
110 5
    public function testAddBindingFailsIfTypeDoesNotAcceptBinding()
111
    {
112 5
        $discovery = $this->createDiscovery();
113 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::CLASS_BINDING));
114 5
        $discovery->addBinding(new StringBinding('string', Foo::clazz));
115
    }
116
117 5 View Code Duplication
    public function testAddBindingAcceptsDuplicates()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
    {
119
        // The idea behind accepting duplicates is that depending on the use
120
        // case, multiple modules may define the same binding but the order
121
        // in which the modules is loaded is important. Hence if we load
122
        // [m1, m2, m3] and m1 and m3 contain the same binding, we cannot simply
123
        // discard one of the bindings, since the order might be important for
124
        // the end user.
125
126 5
        $binding = new StringBinding('string', Foo::clazz);
127
128 5
        $discovery = $this->createDiscovery();
129 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
130 5
        $discovery->addBinding($binding);
131 5
        $discovery->addBinding($binding);
132
133 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
134
135 5
        $this->assertCount(2, $discovery->findBindings(Foo::clazz));
136 5
        $this->assertCount(2, $discovery->getBindings());
137 5
    }
138
139 5
    public function testRemoveBindings()
140
    {
141 5
        $binding1 = new StringBinding('string1', Foo::clazz);
142 5
        $binding2 = new StringBinding('string2', Foo::clazz);
143
144 5
        $discovery = $this->createDiscovery();
145 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
146 5
        $discovery->addBinding($binding1);
147 5
        $discovery->addBinding($binding2);
148 5
        $discovery->removeBindings();
149
150 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
151
152 5
        $this->assertCount(0, $discovery->findBindings(Foo::clazz));
153 5
        $this->assertCount(0, $discovery->getBindings());
154 5
    }
155
156 5 View Code Duplication
    public function testRemoveBindingsDoesNothingIfNoneFound()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
157
    {
158 5
        $discovery = $this->createDiscovery();
159 5
        $discovery->removeBindings();
160
161 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
162
163 5
        $this->assertCount(0, $discovery->getBindings());
164 5
    }
165
166 5
    public function testRemoveBindingsWithType()
167
    {
168 5
        $binding1 = new StringBinding('string1', Foo::clazz);
169 5
        $binding2 = new StringBinding('string2', Foo::clazz);
170 5
        $binding3 = new StringBinding('string3', Bar::clazz);
171
172 5
        $discovery = $this->createDiscovery();
173 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
174 5
        $discovery->addBindingType(new BindingType(Bar::clazz, self::STRING_BINDING));
175 5
        $discovery->addBinding($binding1);
176 5
        $discovery->addBinding($binding2);
177 5
        $discovery->addBinding($binding3);
178 5
        $discovery->removeBindings(Foo::clazz);
179
180 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
181
182 5
        $this->assertEquals(array(), $discovery->findBindings(Foo::clazz));
183 5
        $this->assertEquals(array($binding3), $discovery->findBindings(Bar::clazz));
184 5
        $this->assertEquals(array($binding3), $discovery->getBindings());
185 5
    }
186
187 5 View Code Duplication
    public function testRemoveBindingsWithTypeDoesNothingIfNoneFound()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
188
    {
189 5
        $discovery = $this->createDiscovery();
190 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
191 5
        $discovery->removeBindings(Foo::clazz);
192
193 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
194
195 5
        $this->assertCount(0, $discovery->getBindings());
196 5
    }
197
198 5 View Code Duplication
    public function testRemoveBindingsWithTypeDoesNothingIfTypeNotFound()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
199
    {
200 5
        $discovery = $this->createDiscovery();
201 5
        $discovery->removeBindings(Foo::clazz);
202
203 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
204
205 5
        $this->assertCount(0, $discovery->getBindings());
206 5
    }
207
208
    /**
209
     * @expectedException \InvalidArgumentException
210
     * @expectedExceptionMessage stdClass
211
     */
212 5
    public function testRemoveBindingsWithTypeFailsIfInvalidType()
213
    {
214 5
        $discovery = $this->createDiscovery();
215 5
        $discovery->removeBindings(new stdClass());
0 ignored issues
show
Documentation introduced by
new \stdClass() is of type object<stdClass>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
216
    }
217
218 5 View Code Duplication
    public function testRemoveBindingsWithExpression()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
219
    {
220 5
        $binding1 = new StringBinding('string1', Foo::clazz, array('param1' => 'foo', 'param2' => 'bar'));
221 5
        $binding2 = new StringBinding('string2', Foo::clazz, array('param1' => 'foo'));
222 5
        $binding3 = new StringBinding('string3', Foo::clazz, array('param1' => 'bar'));
223
224 5
        $discovery = $this->createDiscovery();
225 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING, array(
226 5
            new BindingParameter('param1'),
227 5
            new BindingParameter('param2'),
228
        )));
229 5
        $discovery->addBinding($binding1);
230 5
        $discovery->addBinding($binding2);
231 5
        $discovery->addBinding($binding3);
232 5
        $discovery->removeBindings(null, Expr::method('getParameterValue', 'param1', Expr::same('foo')));
233
234 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
235
236 5
        $this->assertEquals(array($binding3), $discovery->findBindings(Foo::clazz));
237 5
        $this->assertEquals(array($binding3), $discovery->getBindings());
238 5
    }
239
240 5 View Code Duplication
    public function testRemoveBindingsWithTypeAndExpression()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
241
    {
242 5
        $binding1 = new StringBinding('string1', Foo::clazz, array('param1' => 'foo', 'param2' => 'bar'));
243 5
        $binding2 = new StringBinding('string2', Foo::clazz, array('param1' => 'foo'));
244 5
        $binding3 = new StringBinding('string3', Foo::clazz, array('param1' => 'bar'));
245
246 5
        $discovery = $this->createDiscovery();
247 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING, array(
248 5
            new BindingParameter('param1'),
249 5
            new BindingParameter('param2'),
250
        )));
251 5
        $discovery->addBinding($binding1);
252 5
        $discovery->addBinding($binding2);
253 5
        $discovery->addBinding($binding3);
254 5
        $discovery->removeBindings(Foo::clazz, Expr::method('getParameterValue', 'param1', Expr::same('foo')));
255
256 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
257
258 5
        $this->assertEquals(array($binding3), $discovery->findBindings(Foo::clazz));
259 5
        $this->assertEquals(array($binding3), $discovery->getBindings());
260 5
    }
261
262 5
    public function testRemoveBindingsWithTypeAndParametersDoesNothingIfNoneFound()
263
    {
264 5
        $discovery = $this->createDiscovery();
265 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
266 5
        $discovery->removeBindings(Foo::clazz, Expr::method('getParameterValue', 'param1', Expr::same('foo')));
267
268 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
269
270 5
        $this->assertCount(0, $discovery->getBindings());
271 5
    }
272
273 5
    public function testRemoveBindingsWithTypeAndParametersDoesNothingIfTypeNotFound()
274
    {
275 5
        $discovery = $this->createDiscovery();
276 5
        $discovery->removeBindings(Foo::clazz, Expr::method('getParameterValue', 'param1', Expr::same('foo')));
277
278 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
279
280 5
        $this->assertCount(0, $discovery->getBindings());
281 5
    }
282
283 5 View Code Duplication
    public function testAddBindingType()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
284
    {
285 5
        $type = new BindingType(Foo::clazz, self::STRING_BINDING);
286
287 5
        $discovery = $this->createDiscovery();
288 5
        $discovery->addBindingType($type);
289
290 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
291
292 5
        $this->assertEquals($type, $discovery->getBindingType(Foo::clazz));
293 5
    }
294
295 5
    public function testAddBindingTypeAfterReadingStorage()
296
    {
297 5
        $type1 = new BindingType(Foo::clazz, self::STRING_BINDING);
298 5
        $type2 = new BindingType(Bar::clazz, self::STRING_BINDING);
299
300 5
        $discovery = $this->createDiscovery();
301 5
        $discovery->addBindingType($type1);
302
303
        // Make sure that the previous call to addBindingType() stored all
304
        // necessary information in order to add further types (e.g. nextId)
305 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
306 5
        $discovery->addBindingType($type2);
307
308 5
        $this->assertEquals($type1, $discovery->getBindingType(Foo::clazz));
309 5
        $this->assertEquals($type2, $discovery->getBindingType(Bar::clazz));
310 5
    }
311
312
    /**
313
     * @expectedException \Puli\Discovery\Api\Type\DuplicateTypeException
314
     * @expectedExceptionMessage Foo
315
     */
316 5
    public function testAddBindingTypeFailsIfAlreadyDefined()
317
    {
318 5
        $discovery = $this->createDiscovery();
319 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
320 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
321
    }
322
323 5 View Code Duplication
    public function testRemoveBindingType()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
324
    {
325 5
        $discovery = $this->createDiscovery();
326 5
        $discovery->addBindingType($type1 = new BindingType(Foo::clazz, self::STRING_BINDING));
327 5
        $discovery->addBindingType(new BindingType(Bar::clazz, self::STRING_BINDING));
328 5
        $discovery->removeBindingType(Bar::clazz);
329
330 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
331
332 5
        $this->assertEquals(array($type1), $discovery->getBindingTypes());
333 5
        $this->assertTrue($discovery->hasBindingType(Foo::clazz));
334 5
        $this->assertFalse($discovery->hasBindingType(Bar::clazz));
335 5
    }
336
337 5
    public function testRemoveBindingTypeIgnoresUnknownTypes()
338
    {
339 5
        $discovery = $this->createDiscovery();
340 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
341 5
        $discovery->removeBindingType(Bar::clazz);
342
343 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
344
345 5
        $this->assertTrue($discovery->hasBindingType(Foo::clazz));
346 5
        $this->assertFalse($discovery->hasBindingType(Bar::clazz));
347 5
    }
348
349
    /**
350
     * @expectedException \InvalidArgumentException
351
     * @expectedExceptionMessage stdClass
352
     */
353 5
    public function testRemoveBindingTypeFailsIfInvalidType()
354
    {
355 5
        $discovery = $this->createDiscovery();
356 5
        $discovery->removeBindingType(new stdClass());
0 ignored issues
show
Documentation introduced by
new \stdClass() is of type object<stdClass>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
357
    }
358
359 5
    public function testRemoveBindingTypeRemovesCorrespondingBindings()
360
    {
361 5
        $discovery = $this->createDiscovery();
362 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
363 5
        $discovery->addBindingType(new BindingType(Bar::clazz, self::STRING_BINDING));
364 5
        $discovery->addBinding($binding1 = new StringBinding('string1', Foo::clazz));
365 5
        $discovery->addBinding($binding2 = new StringBinding('string2', Foo::clazz));
366 5
        $discovery->addBinding($binding3 = new StringBinding('string3', Bar::clazz));
367
368 5
        $discovery->removeBindingType(Foo::clazz);
369
370 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
371
372 5
        $this->assertEquals(array($binding3), $discovery->getBindings());
373 5
    }
374
375 5 View Code Duplication
    public function testRemoveBindingTypes()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
376
    {
377 5
        $discovery = $this->createDiscovery();
378 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
379 5
        $discovery->addBindingType(new BindingType(Bar::clazz, self::STRING_BINDING));
380 5
        $discovery->removeBindingTypes();
381
382 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
383
384 5
        $this->assertEquals(array(), $discovery->getBindingTypes());
385 5
        $this->assertFalse($discovery->hasBindingType(Foo::clazz));
386 5
        $this->assertFalse($discovery->hasBindingType(Bar::clazz));
387 5
    }
388
389 5
    public function testRemoveBindingTypesRemovesBindings()
390
    {
391 5
        $discovery = $this->createDiscovery();
392 5
        $discovery->addBindingType(new BindingType(Foo::clazz, self::STRING_BINDING));
393 5
        $discovery->addBindingType(new BindingType(Bar::clazz, self::STRING_BINDING));
394 5
        $discovery->addBinding($binding1 = new StringBinding('string1', Foo::clazz));
395 5
        $discovery->addBinding($binding2 = new StringBinding('string2', Bar::clazz));
396 5
        $discovery->removeBindingTypes();
397
398 5
        $discovery = $this->loadDiscoveryFromStorage($discovery);
399
400 5
        $this->assertCount(0, $discovery->getBindings());
401 5
    }
402
}
403