Completed
Push — master ( d6446f...d11253 )
by Nelson
05:36
created

testReadonlyPropertiesAreReadables()   B

Complexity

Conditions 3
Paths 1

Size

Total Lines 37
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 24
nc 1
nop 3
dl 0
loc 37
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * PHP: Nelson Martell Library file
4
 *
5
 * Content:
6
 * - Trait definition
7
 *
8
 * Copyright © 2017 Nelson Martell (http://nelson6e65.github.io)
9
 *
10
 * Licensed under The MIT License (MIT)
11
 * For full copyright and license information, please see the LICENSE
12
 * Redistributions of files must retain the above copyright notice.
13
 *
14
 * @copyright 2017 Nelson Martell
15
 * @link      http://nelson6e65.github.io/php_nml/
16
 * @since     v0.7.0
17
 * @license   http://www.opensource.org/licenses/mit-license.php The MIT License (MIT)
18
 * */
19
20
namespace NelsonMartell\Test\Helpers;
21
22
use Cake\Utility\Inflector;
23
use NelsonMartell\Extensions\Text;
24
use NelsonMartell\IStrictPropertiesContainer;
25
use SebastianBergmann\Exporter\Exporter;
26
use BadMethodCallException;
27
28
/**
29
 * Split of ImplementsIStrictPropertiesContainer, for classes implementing any write-only property.
30
 *
31
 * @author Nelson Martell <[email protected]>
32
 * */
33
trait HasReadOnlyProperties
34
{
35
    /**
36
     * ImplementsIStrictPropertiesContainer trait provides this method implementation.
37
     *
38
     * @returns IStrictPropertiesContainer
39
     * @see ImplementsIStrictPropertiesContainer::testImplementsIStrictPropertiesContainerInterface()
40
     */
41
    public abstract function testImplementsIStrictPropertiesContainerInterface($obj);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
42
43
    public abstract function readonlyPropertiesProvider();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
44
45
46
    /**
47
     * @depends testImplementsIStrictPropertiesContainerInterface
48
     *
49
     * @dataProvider readonlyPropertiesProvider
50
     */
51
    public function testReadonlyPropertiesAreReadables(
52
        IStrictPropertiesContainer $obj,
53
        $property,
54
        $expected
55
    ) {
56
        try {
57
            $actual = $obj->$property;
58
        } catch (BadMethodCallException $e) {
0 ignored issues
show
Unused Code introduced by
catch (\BadMethodCallExc...this->fail($message); } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
59
            $message = Text::format(
60
                'Property `{1}` it should be accessible, but does it throws an exception: "{2}".',
61
                get_class($obj),
62
                $property,
63
                $e->getMessage()
64
            );
65
66
            $this->fail($message);
67
        }
68
69
        $exporter = new Exporter();
70
71
        $var = get_class($obj);
72
        $var = Inflector::variable(substr(
73
            $var,
74
            strrpos($var, '\\') === false ? 0 : strrpos($var, '\\') + 1
75
        ));
76
77
        $message = Text::format(
78
            '$actual = ${var}->{property}; // {actual}',
79
            [
80
                'var'      => $var,
81
                'property' => $property,
82
                'actual'   => $exporter->shortenedExport($actual)
83
            ]
84
        );
85
86
        $this->assertEquals($expected, $actual, $message);
0 ignored issues
show
Bug introduced by
It seems like assertEquals() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
87
    }
88
89
    /**
90
     * @depends testImplementsIStrictPropertiesContainerInterface
91
     * @dataProvider readonlyPropertiesProvider
92
     * @expectedException \BadMethodCallException
93
     */
94
    public function testReadonlyPropertiesAreNotWritables(
95
        IStrictPropertiesContainer $obj = null,
96
        $property = null,
97
        $value = null
98
    ) {
99
        $obj->$property = $value;
100
    }
101
}
102