Completed
Push — v2 ( e198fb...470733 )
by Joschi
04:46
created

ItemTest::testItemObjectModelAlternates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 0
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * micrometa
5
 *
6
 * @category Jkphl
7
 * @package Jkphl\Micrometa
8
 * @subpackage Infrastructure
9
 * @author Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright Copyright © 2017 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2017 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Jkphl\Micrometa\Tests\Ports;
38
39
use Jkphl\Micrometa\Infrastructure\Factory\MicroformatsFactory;
40
use Jkphl\Micrometa\Ports\Item\Item;
41
use Jkphl\Micrometa\Ports\Item\ItemInterface;
42
use Jkphl\Micrometa\Ports\Item\ItemList;
43
44
/**
45
 * Parser factory tests
46
 *
47
 * @package Jkphl\Micrometa
48
 * @subpackage Jkphl\Micrometa\Tests
49
 */
50
class ItemTest extends AbstractItemListTest
51
{
52
    /**
53
     * Test an item
54
     */
55
    public function testItemTypes()
56
    {
57
        $feedItem = $this->getFeedItem();
58
        $this->assertInstanceOf(Item::class, $feedItem);
59
60
        // Test the item type
61
        $this->assertTrue($feedItem->isOfType('h-feed'));
62
        $this->assertTrue($feedItem->isOfType('h-feed', MicroformatsFactory::MF2_PROFILE_URI));
63
        $this->assertFalse($feedItem->isOfType('invalid', MicroformatsFactory::MF2_PROFILE_URI));
64
    }
65
66
    /**
67
     * Test the item properties
68
     *
69
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
70
     * @expectedExceptionCode 1491672553
71
     */
72
    public function testItemProperties()
73
    {
74
        $feedItem = $this->getFeedItem();
75
        $this->assertInstanceOf(Item::class, $feedItem);
76
77
        $properties = $feedItem->getProperties();
78
        $this->assertTrue(is_array($properties));
79
        $this->assertEquals(3, count($properties));
80
81
        // Get an unknown property
82
        $feedItem->getProperty('name', null, 2);
83
    }
84
85
    /**
86
     * Test the item export
87
     */
88
    public function testItemExport()
89
    {
90
        $feedItem = $this->getFeedItem();
91
        $this->assertInstanceOf(Item::class, $feedItem);
92
93
        $export = $feedItem->toObject();
94
        $this->assertInstanceOf(\stdClass::class, $export);
95
        foreach (['format', 'types', 'properties', 'items'] as $property) {
96
            $this->assertTrue(isset($export->$property));
97
        }
98
    }
99
100
    /**
101
     * Test an unprofiled property
102
     *
103
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
104
     * @expectedExceptionCode 1488315604
105
     */
106
    public function testItemUnprofiledProperty()
107
    {
108
        $feedItem = $this->getFeedItem();
109
        $this->assertInstanceOf(Item::class, $feedItem);
110
111
        // Test the item name as an unprofiled property value list
112
        $feedNameList = $feedItem->getProperty('name');
113
        $this->assertTrue(is_array($feedNameList));
114
        $this->assertEquals(1, count($feedNameList));
115
        $this->assertTrue(is_string($feedNameList[0]));
116
        $this->assertEquals('John Doe\'s Blog', $feedNameList[0]);
117
118
        // Test the item name as an unprofiled single property value
119
        $feedName = $feedItem->getProperty('name', null, 0);
120
        $this->assertTrue(is_string($feedName));
121
        $this->assertEquals('John Doe\'s Blog', $feedName);
122
123
        // Test an invalid unprofiled property
124
        $feedItem->getProperty('invalid');
125
    }
126
127
    /**
128
     * Test a profiled property
129
     *
130
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
131
     * @expectedExceptionCode 1488315604
132
     */
133
    public function testItemProfiledProperty()
134
    {
135
        $feedItem = $this->getFeedItem();
136
        $this->assertInstanceOf(Item::class, $feedItem);
137
138
        // Test the item name as an unprofiled property value list
139
        $feedNameList = $feedItem->getProperty('name', MicroformatsFactory::MF2_PROFILE_URI);
140
        $this->assertTrue(is_array($feedNameList));
141
        $this->assertEquals(1, count($feedNameList));
142
        $this->assertTrue(is_string($feedNameList[0]));
143
        $this->assertEquals('John Doe\'s Blog', $feedNameList[0]);
144
145
        // Test the item name as an unprofiled single property value
146
        $feedName = $feedItem->getProperty('name', MicroformatsFactory::MF2_PROFILE_URI, 0);
147
        $this->assertTrue(is_string($feedName));
148
        $this->assertEquals('John Doe\'s Blog', $feedName);
149
150
        // Test an invalid unprofiled property
151
        $feedItem->getProperty('invalid', MicroformatsFactory::MF2_PROFILE_URI);
152
    }
153
154
    /**
155
     * Test an unprofiled property
156
     *
157
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
158
     * @expectedExceptionCode 1488315604
159
     */
160
    public function testItemAliasedProperty()
161
    {
162
        $feedItem = $this->getFeedItem();
163
        $this->assertInstanceOf(Item::class, $feedItem);
164
165
        // Test the custom item property as an unprofiled property value list
166
        $feedCustomPropList = $feedItem->getProperty('custom-property');
167
        $this->assertTrue(is_array($feedCustomPropList));
168
        $this->assertEquals(1, count($feedCustomPropList));
169
        $this->assertTrue(is_string($feedCustomPropList[0]));
170
        $this->assertEquals('Property for alias testing', $feedCustomPropList[0]);
171
172
        // Test the custom item property as an unprofiled single property value
173
        $feedCustomProp = $feedItem->getProperty('custom-property', null, 0);
174
        $this->assertTrue(is_string($feedCustomProp));
175
        $this->assertEquals('Property for alias testing', $feedCustomProp);
176
177
        // Test the custom item property via the convenience getter
178
        $feedCustomProp = $feedItem->customProperty;
1 ignored issue
show
Bug introduced by
The property customProperty does not seem to exist in Jkphl\Micrometa\Ports\Item\Item.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
179
        $this->assertTrue(is_string($feedCustomProp));
180
        $this->assertEquals('Property for alias testing', $feedCustomProp);
181
182
        // Test an invalid property
183
        $feedItem->invalidProperty;
1 ignored issue
show
Documentation introduced by
The property invalidProperty does not exist on object<Jkphl\Micrometa\Ports\Item\Item>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
184
    }
185
186
    /**
187
     * Test a property stack
188
     *
189
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
190
     * @expectedExceptionCode 1488315604
191
     */
192
    public function testItemPropertyStack()
193
    {
194
        $feedItem = $this->getFeedItem();
195
        $this->assertInstanceOf(Item::class, $feedItem);
196
197
        // Request a valid property stack
198
        $propertyValues = $feedItem->getFirstProperty('photo', MicroformatsFactory::MF2_PROFILE_URI, 'name');
199
        $this->assertEquals(['John Doe\'s Blog'], $propertyValues);
200
201
        // Request unknown properties only
202
        $feedItem->getFirstProperty('photo', MicroformatsFactory::MF2_PROFILE_URI, 'invalid');
203
    }
204
205
    /**
206
     * Test a property item
207
     */
208
    public function testItemPropertyItem()
209
    {
210
        $feedItem = $this->getFeedItem();
211
        $this->assertInstanceOf(Item::class, $feedItem);
212
213
        // Request a valid property stack
214
        /** @var ItemInterface[] $authors */
215
        $authors = $feedItem->getFirstProperty('author');
216
        $this->assertTrue(is_array($authors));
217
        $this->assertInstanceOf(ItemInterface::class, $authors[0]);
218
219
        // Test the author name as an unprofiled single property value
220
        $authorName = $authors[0]->getProperty('name', MicroformatsFactory::MF2_PROFILE_URI, 0);
221
        $this->assertTrue(is_string($authorName));
222
        $this->assertEquals('John Doe', $authorName);
223
    }
224
225
    /**
226
     * Test nested items
227
     *
228
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\InvalidArgumentException
229
     * @expectedExceptionCode 1492418709
230
     */
231
    public function testItemNestedItems()
232
    {
233
        $feedItem = $this->getFeedItem();
234
        $this->assertInstanceOf(Item::class, $feedItem);
235
236
        // Test the number of nested items
237
        $this->assertEquals(2, count($feedItem));
238
        $this->assertEquals(2, count($feedItem->getItems()));
239
        foreach ($feedItem as $itemIndex => $entryItem) {
240
            $this->assertInstanceOf(ItemInterface::class, $entryItem);
241
            $this->assertTrue(is_int($itemIndex));
242
        }
243
        $this->assertInstanceOf(ItemInterface::class, $feedItem->getFirstItem('h-entry'));
244
        $this->assertInstanceOf(
245
            ItemInterface::class, $feedItem->getFirstItem('h-entry', MicroformatsFactory::MF2_PROFILE_URI)
246
        );
247
248
        // Test the second entry item
249
        /** @var Item $entryItem */
250
        $entryItem = $feedItem->getItems('h-entry')[1];
251
        $this->assertInstanceOf(ItemInterface::class, $entryItem);
252
253
        // Test the magic item getter / item type aliases
254
        /** @noinspection PhpUndefinedMethodInspection */
255
        $entryItem = $feedItem->hEntry(0);
1 ignored issue
show
Documentation Bug introduced by
The method hEntry does not exist on object<Jkphl\Micrometa\Ports\Item\Item>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
256
        $this->assertInstanceOf(ItemInterface::class, $entryItem);
257
        /** @noinspection PhpUndefinedMethodInspection */
258
        $feedItem->hEntry(-1);
1 ignored issue
show
Documentation Bug introduced by
The method hEntry does not exist on object<Jkphl\Micrometa\Ports\Item\Item>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
259
    }
260
261
    /**
262
     * Test non-existent nested item
263
     *
264
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
265
     * @expectedExceptionCode 1492418999
266
     */
267
    public function testItemNonExistentNestedItems()
268
    {
269
        $feedItem = $this->getFeedItem();
270
        /** @noinspection PhpUndefinedMethodInspection */
271
        $this->assertEquals('John Doe', $feedItem->hEntry()->author->name);
1 ignored issue
show
Documentation Bug introduced by
The method hEntry does not exist on object<Jkphl\Micrometa\Ports\Item\Item>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
272
        /** @noinspection PhpUndefinedMethodInspection */
273
        $feedItem->hEntry(2);
1 ignored issue
show
Documentation Bug introduced by
The method hEntry does not exist on object<Jkphl\Micrometa\Ports\Item\Item>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
274
    }
275
276
    /**
277
     * Test the item list export
278
     *
279
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
280
     * @expectedExceptionCode 1492030227
281
     */
282
    public function testItemListExport()
283
    {
284
        $feedItem = $this->getFeedItem();
285
        $itemList = new ItemList([$feedItem]);
286
        $this->assertInstanceOf(ItemList::class, $itemList);
287
288
        $export = $itemList->toObject();
289
        $this->assertInstanceOf(\stdClass::class, $export);
290
        $this->assertTrue(isset($export->items));
291
        $this->assertTrue(is_array($export->items));
292
        $this->assertEquals($feedItem->toObject(), current($export->items));
293
294
        $itemList->getFirstItem('invalid');
295
    }
296
}
297