Completed
Push — master ( 68c6f3...91ba10 )
by Joschi
02:27
created

ObjectTest::testObjectFacadeRelative()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 1
Metric Value
c 5
b 0
f 1
dl 0
loc 10
rs 9.4285
cc 3
eloc 5
nc 3
nop 0
1
<?php
2
3
/**
4
 * apparat-object
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Object
8
 * @subpackage  Apparat\Object\Infrastructure
9
 * @author      Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright   Copyright © 2016 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 © 2016 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 Apparat\Object\Tests;
38
39
use Apparat\Object\Application\Factory\ObjectFactory;
40
use Apparat\Object\Application\Model\Object\Article;
41
use Apparat\Object\Domain\Factory\AuthorFactory;
42
use Apparat\Object\Domain\Model\Author\ApparatAuthor;
43
use Apparat\Object\Domain\Model\Object\AbstractObject;
44
use Apparat\Object\Domain\Model\Object\Id;
45
use Apparat\Object\Domain\Model\Object\ResourceInterface;
46
use Apparat\Object\Domain\Model\Object\Revision;
47
use Apparat\Object\Domain\Model\Object\Type;
48
use Apparat\Object\Domain\Model\Path\RepositoryPath;
49
use Apparat\Object\Domain\Model\Properties\SystemProperties;
50
use Apparat\Object\Domain\Repository\Repository;
51
use Apparat\Object\Infrastructure\Repository\FileAdapterStrategy;
52
use Apparat\Object\Ports\Object;
53
use Apparat\Object\Ports\Repository as RepositoryFactory;
54
55
/**
56
 * Object tests
57
 *
58
 * @package Apparat\Object
59
 * @subpackage ApparatTest
60
 */
61
class ObjectTest extends AbstractDisabledAutoconnectorTest
62
{
63
    /**
64
     * Example object path
65
     *
66
     * @var string
67
     */
68
    const OBJECT_PATH = '/2015/12/21/1.article/1';
69
    /**
70
     * Test repository
71
     *
72
     * @var Repository
73
     */
74
    protected static $repository = null;
75
76
    /**
77
     * Setup
78
     */
79
    public static function setUpBeforeClass()
80
    {
81
        \Apparat\Object\Ports\Repository::register(
82
            getenv('REPOSITORY_URL'),
83
            [
84
                'type' => FileAdapterStrategy::TYPE,
85
                'root' => __DIR__.DIRECTORY_SEPARATOR.'Fixture',
86
            ]
87
        );
88
89
        self::$repository = \Apparat\Object\Ports\Repository::instance(getenv('REPOSITORY_URL'));
90
91
        \date_default_timezone_set('UTC');
92
    }
93
94
    /**
95
     * Tears down the fixture
96
     */
97
    public function tearDown()
98
    {
99
        TestType::removeInvalidType();
100
        parent::tearDown();
101
    }
102
103
    /**
104
     * Test undefined object type
105
     *
106
     * @expectedException \Apparat\Object\Application\Factory\InvalidArgumentException
107
     * @expectedExceptionCode 1450905868
108
     */
109
    public function testUndefinedObjectType()
110
    {
111
        $resource = $this->getMock(ResourceInterface::class);
112
        $resource->method('getPropertyData')->willReturn([]);
113
        $repositoryPath = $this->getMockBuilder(RepositoryPath::class)->disableOriginalConstructor()->getMock();
114
115
        /** @var ResourceInterface $resource */
116
        /** @var RepositoryPath $repositoryPath */
117
        ObjectFactory::createFromResource($repositoryPath, $resource);
118
    }
119
120
    /**
121
     * Test invalid object type
122
     *
123
     * @expectedException \Apparat\Object\Domain\Model\Object\InvalidArgumentException
124
     * @expectedExceptionCode 1449871242
125
     */
126
    public function testInvalidObjectType()
127
    {
128
        $resource = $this->getMock(ResourceInterface::class);
129
        $resource->method('getPropertyData')->willReturn([SystemProperties::COLLECTION => ['type' => 'invalid']]);
130
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
131
132
        /** @var ResourceInterface $resource */
133
        ObjectFactory::createFromResource($articleObjectPath, $resource);
134
    }
135
136
    /**
137
     * Load an article object and test basic properties
138
     */
139
    public function testLoadArticleObject()
140
    {
141
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
142
        $articleObject = self::$repository->loadObject($articleObjectPath);
143
        $this->assertEquals(
144
            getenv('APPARAT_BASE_URL').getenv('REPOSITORY_URL').self::OBJECT_PATH,
145
            $articleObject->getAbsoluteUrl()
146
        );
147
    }
148
149
    /**
150
     * Load an article object and test its system properties
151
     */
152
    public function testLoadArticleObjectSystemProperties()
153
    {
154
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
155
        $articleObject = self::$repository->loadObject($articleObjectPath);
156
        $this->assertInstanceOf(Article::class, $articleObject);
157
        $this->assertEquals(new Id(1), $articleObject->getId());
158
        $this->assertEquals(new Type(Type::ARTICLE), $articleObject->getType());
159
        $this->assertEquals(new Revision(1), $articleObject->getRevision());
160
        $this->assertFalse($articleObject->isDraft());
161
        $this->assertEquals(new \DateTimeImmutable('2015-12-21T22:30:00'), $articleObject->getCreated());
162
        $this->assertEquals(new \DateTimeImmutable('2015-12-21T22:45:00'), $articleObject->getPublished());
163
        $this->assertEquals('a123456789012345678901234567890123456789', $articleObject->getHash());
164
        $this->assertEquals(
165
            "# Example article object\n\nThis file is an example for an object of type `\"article\"`.\n",
166
            $articleObject->getPayload()
167
        );
168
    }
169
170
    /**
171
     * Load an article object and test its meta properties
172
     */
173
    public function testLoadArticleObjectMetaProperties()
174
    {
175
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
176
        $articleObject = self::$repository->loadObject($articleObjectPath);
177
        $this->assertInstanceOf(Article::class, $articleObject);
178
        $this->assertEquals('Example article object', $articleObject->getDescription());
179
        $this->assertEquals(
180
            'Article objects feature a Markdown payload along with some custom properties',
181
            $articleObject->getAbstract()
182
        );
183
        $this->assertArrayEquals(['apparat', 'object', 'example', 'article'], $articleObject->getKeywords());
184
        $this->assertArrayEquals(['example', 'text'], $articleObject->getCategories());
185
186
        $authorCount = count($articleObject->getAuthors());
187
        $articleObject->addAuthor(AuthorFactory::createFromString(AuthorTest::GENERIC_AUTHOR));
188
        $this->assertEquals($authorCount + 1, count($articleObject->getAuthors()));
189
    }
190
191
    /**
192
     * Load an article object and test its domain properties
193
     *
194
     * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
195
     * @expectedExceptionCode 1450818168
196
     */
197
    public function testLoadArticleObjectDomainProperties()
198
    {
199
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
200
        $articleObject = self::$repository->loadObject($articleObjectPath);
201
        $this->assertEquals('/system/url', $articleObject->getDomainProperty('uid'));
202
        $this->assertEquals('value', $articleObject->getDomainProperty('group:single'));
203
        $articleObject->getDomainProperty('group:invalid');
204
    }
205
206
    /**
207
     * Load an article object and test an empty domain property name
208
     *
209
     * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
210
     * @expectedExceptionCode 1450817720
211
     */
212
    public function testLoadArticleObjectDomainEmptyProperty()
213
    {
214
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
215
        $articleObject = self::$repository->loadObject($articleObjectPath);
216
        $articleObject->getDomainProperty('');
217
    }
218
219
    /**
220
     * Test the object facade with an absolute object URL
221
     */
222
    public function testObjectFacadeAbsolute()
223
    {
224
        $object = Object::instance(getenv('APPARAT_BASE_URL').getenv('REPOSITORY_URL').self::OBJECT_PATH);
225
        $this->assertInstanceOf(Article::class, $object);
226
    }
227
228
    /**
229
     * Test the object facade with a relative object URL
230
     */
231
    public function testObjectFacadeRelative()
232
    {
233
        $object = Object::instance(getenv('REPOSITORY_URL').self::OBJECT_PATH);
234
        $this->assertInstanceOf(Article::class, $object);
235
        foreach ($object->getAuthors() as $author) {
236
            if ($author instanceof ApparatAuthor) {
237
//				echo $author->getId()->getId();
238
            }
239
        }
240
    }
241
242
    /**
243
     * Test the object facade with an invalid relative object URL
244
     *
245
     * @expectedException \Apparat\Resource\Infrastructure\Io\File\InvalidArgumentException
246
     * @expectedExceptionCode 1447616824
247
     */
248
    public function testObjectFacadeRelativeInvalid()
249
    {
250
        $object = Object::instance(getenv('REPOSITORY_URL').'/2015/12/21/2.article/2');
251
        $this->assertInstanceOf(Article::class, $object);
252
    }
253
254
    /**
255
     * Test with a missing object type class
256
     *
257
     * @expectedException \Apparat\Object\Application\Factory\InvalidArgumentException
258
     * @expectedExceptionCode 1450824842
259
     */
260
    public function testInvalidObjectTypeClass()
261
    {
262
        TestType::addInvalidType();
263
264
        $resource = $this->getMock(ResourceInterface::class);
265
        $resource->method('getPropertyData')->willReturn([SystemProperties::COLLECTION => ['type' => 'invalid']]);
266
        $articleObjectPath = new RepositoryPath(self::$repository, '/2016/02/16/5.invalid/5');
267
268
        /** @var ResourceInterface $resource */
269
        ObjectFactory::createFromResource($articleObjectPath, $resource);
270
    }
271
272
    /**
273
     * Test instantiation of object with invalid domain properties collection
274
     *
275
     * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
276
     * @expectedExceptionCode 1452288429
277
     */
278
    public function testInvalidDomainPropertyCollectionClass()
279
    {
280
        $this->getMockBuilder(AbstractObject::class)
281
            ->setConstructorArgs([new RepositoryPath(self::$repository, self::OBJECT_PATH)])
282
            ->getMock();
283
    }
284
285
    /**
286
     * Test the property data
287
     */
288
    public function testObjectPropertyData()
289
    {
290
//  $frontMarkResource = Resource::frontMark('file://'.__DIR__.DIRECTORY_SEPARATOR.'Fixture'.self::OBJECT_PATH.'.md');
291
        $object = Object::instance(getenv('REPOSITORY_URL').self::OBJECT_PATH);
292
        $this->assertTrue(is_array($object->getPropertyData()));
293
//        print_r($frontMarkResource->getData());
294
//        print_r($object->getPropertyData());
295
    }
296
297
    /**
298
     * Test the property data
299
     */
300
    public function testMetaDataMutation()
301
    {
302
        $object = Object::instance(getenv('REPOSITORY_URL').self::OBJECT_PATH);
303
        $this->assertTrue(is_array($object->getPropertyData()));
304
        $object->setDescription('Example article objectq');
305
    }
306
307
    /**
308
     * Test the creation and persisting of an article object
309
     */
310
    public function testCreateArticleObject()
311
    {
312
        // Create a temporary repository
313
        $tempRepoDirectory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'temp-repo';
314
        $fileRepository = RepositoryFactory::create(
315
            getenv('REPOSITORY_URL'),
316
            [
317
                'type' => FileAdapterStrategy::TYPE,
318
                'root' => $tempRepoDirectory,
319
            ]
320
        );
321
        $this->assertInstanceOf(Repository::class, $fileRepository);
322
323
        // Create a new article in the temporary repository
324
        $payload = md5(rand());
325
        $article = $fileRepository->createObject(Type::ARTICLE, $payload);
0 ignored issues
show
Bug introduced by
The method createObject() does not exist on Apparat\Object\Ports\Repository. Did you maybe mean create()?

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...
326
        $this->assertInstanceOf(Article::class, $article);
327
        $this->assertEquals($payload, $article->getPayload());
328
        $this->assertFileExists($tempRepoDirectory.
329
            str_replace('/', DIRECTORY_SEPARATOR, $article->getRepositoryPath()
330
                ->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))));
331
332
        // Delete temporary repository
333
        $this->deleteRecursive($tempRepoDirectory);
334
    }
335
336
    /**
337
     * Recursively register a directory and all nested files and directories for deletion on teardown
338
     *
339
     * @param string $directory Directory
340
     */
341
    protected function deleteRecursive($directory)
342
    {
343
        $this->tmpFiles[] = $directory;
344
        foreach (scandir($directory) as $item) {
345
            if (!preg_match('%^\.+$%', $item)) {
346
                $path = $directory.DIRECTORY_SEPARATOR.$item;
347
                if (is_dir($path)) {
348
                    $this->deleteRecursive($path);
349
                } else {
350
                    $this->tmpFiles[] = $path;
351
                }
352
            }
353
        }
354
    }
355
}
356