MissingObjectTripleNodeSimplifierTest   B
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 18

Importance

Changes 0
Metric Value
wmc 5
lcom 0
cbo 18
dl 0
loc 162
rs 7.3333
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A buildSimplifier() 0 9 1
A simplifiableProvider() 0 18 1
A nonSimplifiableProvider() 0 21 1
A testSimplification() 0 20 1
B simplificationProvider() 0 78 1
1
<?php
2
3
namespace PPP\Wikidata\TreeSimplifier;
4
5
use DataValues\StringValue;
6
use PPP\DataModel\AbstractNode;
7
use PPP\DataModel\MissingNode;
8
use PPP\DataModel\ResourceListNode;
9
use PPP\DataModel\StringResourceNode;
10
use PPP\DataModel\TripleNode;
11
use PPP\Wikidata\WikibaseResourceNode;
12
use Wikibase\DataModel\Entity\EntityIdValue;
13
use Wikibase\DataModel\Entity\Item;
14
use Wikibase\DataModel\Entity\ItemId;
15
use Wikibase\DataModel\Entity\PropertyId;
16
use Wikibase\DataModel\Snak\PropertySomeValueSnak;
17
use Wikibase\DataModel\Snak\PropertyValueSnak;
18
use Wikibase\DataModel\Statement\Statement;
19
use Wikibase\EntityStore\InMemory\InMemoryEntityStore;
20
21
/**
22
 * @covers PPP\Wikidata\TreeSimplifier\MissingObjectTripleNodeSimplifier
23
 *
24
 * @licence AGPLv3+
25
 * @author Thomas Pellissier Tanon
26
 */
27
class MissingObjectTripleNodeSimplifierTest extends NodeSimplifierBaseTest {
28
29
	public function buildSimplifier() {
30
		$resourceListNodeParserMock = $this->getMockBuilder('PPP\Wikidata\ValueParsers\ResourceListNodeParser')
31
			->disableOriginalConstructor()
32
			->getMock();
33
		$resourceListForEntityPropertyMock = $this->getMockBuilder('PPP\Wikidata\TreeSimplifier\ResourceListForEntityProperty')
34
			->disableOriginalConstructor()
35
			->getMock();
36
		return new MissingObjectTripleNodeSimplifier($resourceListNodeParserMock, $resourceListForEntityPropertyMock);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \PPP\Wikidata...ForEntityPropertyMock); (PPP\Wikidata\TreeSimplif...ectTripleNodeSimplifier) is incompatible with the return type declared by the abstract method PPP\Wikidata\TreeSimplif...seTest::buildSimplifier of type PPP\Wikidata\TreeSimplifier\NodeSimplifier.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
37
	}
38
39
	/**
40
	 * @see NodeSimplifierBaseTest::simplifiableProvider
41
	 */
42
	public function simplifiableProvider() {
43
		return array(
44
			array(
45
				new TripleNode(
46
					new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new ItemId('Q42'))))),
47
					new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new PropertyId('P214'))))),
48
					new MissingNode()
49
				)
50
			),
51
			array(
52
				new TripleNode(
53
					new ResourceListNode(array(new StringResourceNode('Douglas Adams'))),
54
					new ResourceListNode(array(new StringResourceNode('VIAF'))),
55
					new MissingNode()
56
				)
57
			),
58
		);
59
	}
60
61
	/**
62
	 * @see NodeSimplifierBaseTest::nonSimplifiableProvider
63
	 */
64
	public function nonSimplifiableProvider() {
65
		return array(
66
			array(
67
				new MissingNode()
68
			),
69
			array(
70
				new TripleNode(
71
					new MissingNode(),
72
					new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new PropertyId('P214'))))),
73
					new ResourceListNode(array(new WikibaseResourceNode('', new StringValue('113230702'))))
74
				)
75
			),
76
			array(
77
				new TripleNode(
78
					new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new ItemId('Q42'))))),
79
					new MissingNode(),
80
					new ResourceListNode(array(new WikibaseResourceNode('', new StringValue('113230702'))))
81
				)
82
			),
83
		);
84
	}
85
86
	/**
87
	 * @dataProvider simplificationProvider
88
	 */
89
	public function testSimplification(TripleNode $queryNode, AbstractNode $responseNodes, Item $item, PropertyId $propertyId) {
90
		$resourceListNodeParserMock = $this->getMockBuilder('PPP\Wikidata\ValueParsers\ResourceListNodeParser')
91
			->disableOriginalConstructor()
92
			->getMock();
93
		$resourceListNodeParserMock->expects($this->any())
94
			->method('parse')
95
			->will($this->onConsecutiveCalls(
96
				new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue($item->getId())))),
0 ignored issues
show
Bug introduced by
It seems like $item->getId() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
97
				new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue($propertyId))))
98
			));
99
100
		$simplifier = new MissingObjectTripleNodeSimplifier(
101
			$resourceListNodeParserMock,
102
			new ResourceListForEntityProperty(new InMemoryEntityStore(array($item)))
103
		);
104
		$this->assertEquals(
105
			$responseNodes,
106
			$simplifier->simplify($queryNode)
107
		);
108
	}
109
110
	public function simplificationProvider() {
111
		$list = array();
112
113
		//Value
114
		$douglasAdamItem = new Item();
115
		$douglasAdamItem->setId(new ItemId('Q42'));
116
		$birthPlaceStatement = new Statement(
117
			new PropertyValueSnak(new PropertyId('P214'), new StringValue('113230702'))
118
		);
119
		$birthPlaceStatement->setGuid('42');
120
		$douglasAdamItem->getStatements()->addStatement($birthPlaceStatement);
121
		$list[] = array(
122
			new TripleNode(
123
				new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new ItemId('Q42'))))),
124
				new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new PropertyId('P214'))))),
125
				new MissingNode()
126
			),
127
			new ResourceListNode(array(
128
				new ResourceListNode(array(
129
					new WikibaseResourceNode(
130
						'',
131
						new StringValue('113230702'),
132
						new ItemId('Q42'),
133
						new PropertyId('P214')
134
					)
135
				))
136
			)),
137
			$douglasAdamItem,
138
			new PropertyId('P214')
139
		);
140
141
		//SomeValue
142
		$douglasAdamItem = new Item();
143
		$douglasAdamItem->setId(new ItemId('Q42'));
144
		$birthPlaceStatement = new Statement(new PropertySomeValueSnak(new PropertyId('P19')));
145
		$birthPlaceStatement->setGuid('42');
146
		$douglasAdamItem->getStatements()->addStatement($birthPlaceStatement);
147
		$list[] = array(
148
			new TripleNode(
149
				new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new ItemId('Q42'))))),
150
				new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new PropertyId('P19'))))),
151
				new MissingNode()
152
			),
153
			new ResourceListNode(array()),
154
			$douglasAdamItem,
155
			new PropertyId('P19')
156
		);
157
158
		//No result
159
		$douglasAdamItem = new Item();
160
		$douglasAdamItem->setId(new ItemId('Q42'));
161
		$list[] = array(
162
			new TripleNode(
163
				new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new ItemId('Q42'))))),
164
				new ResourceListNode(array(new WikibaseResourceNode('', new EntityIdValue(new PropertyId('P19'))))),
165
				new MissingNode()
166
			),
167
			new ResourceListNode(array()),
168
			$douglasAdamItem,
169
			new PropertyId('P19')
170
		);
171
172
		//Parsing
173
		$douglasAdamItem = new Item();
174
		$douglasAdamItem->setId(new ItemId('Q42'));
175
		$list[] = array(
176
			new TripleNode(
177
				new ResourceListNode(array(new StringResourceNode('Douglas Adams'))),
178
				new ResourceListNode(array(new StringResourceNode('VIAF'))),
179
				new MissingNode()
180
			),
181
			new ResourceListNode(array()),
182
			$douglasAdamItem,
183
			new PropertyId('P214')
184
		);
185
186
		return $list;
187
	}
188
}
189