Completed
Push — master ( 1587a0...b0ef19 )
by Joschi
04:29
created

ObjectTest::tearDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
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($resource, $repositoryPath);
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($resource, $articleObjectPath);
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->assertEquals(new \DateTimeImmutable('2015-12-21T22:30:00'), $articleObject->getCreated());
161
        $this->assertEquals(new \DateTimeImmutable('2015-12-21T22:45:00'), $articleObject->getPublished());
162
        $this->assertEquals('a123456789012345678901234567890123456789', $articleObject->getHash());
163
        $this->assertEquals(
164
            "# Example article object\n\nThis file is an example for an object of type `\"article\"`.\n",
165
            $articleObject->getPayload()
166
        );
167
    }
168
169
    /**
170
     * Load an article object and test its meta properties
171
     */
172
    public function testLoadArticleObjectMetaProperties()
173
    {
174
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
175
        $articleObject = self::$repository->loadObject($articleObjectPath);
176
        $this->assertInstanceOf(Article::class, $articleObject);
177
        $this->assertEquals('Example article object', $articleObject->getDescription());
178
        $this->assertEquals(
179
            'Article objects feature a Markdown payload along with some custom properties',
180
            $articleObject->getAbstract()
181
        );
182
        $this->assertArrayEquals(['apparat', 'object', 'example', 'article'], $articleObject->getKeywords());
183
        $this->assertArrayEquals(['example', 'text'], $articleObject->getCategories());
184
185
        $authorCount = count($articleObject->getAuthors());
186
        $articleObject->addAuthor(AuthorFactory::createFromString(AuthorTest::GENERIC_AUTHOR));
187
        $this->assertEquals($authorCount + 1, count($articleObject->getAuthors()));
188
    }
189
190
    /**
191
     * Load an article object and test its domain properties
192
     *
193
     * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
194
     * @expectedExceptionCode 1450818168
195
     */
196
    public function testLoadArticleObjectDomainProperties()
197
    {
198
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
199
        $articleObject = self::$repository->loadObject($articleObjectPath);
200
        $this->assertEquals('/system/url', $articleObject->getDomainProperty('uid'));
201
        $this->assertEquals('value', $articleObject->getDomainProperty('group:single'));
202
        $articleObject->getDomainProperty('group:invalid');
203
    }
204
205
    /**
206
     * Load an article object and test an empty domain property name
207
     *
208
     * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
209
     * @expectedExceptionCode 1450817720
210
     */
211
    public function testLoadArticleObjectDomainEmptyProperty()
212
    {
213
        $articleObjectPath = new RepositoryPath(self::$repository, self::OBJECT_PATH);
214
        $articleObject = self::$repository->loadObject($articleObjectPath);
215
        $articleObject->getDomainProperty('');
216
    }
217
218
    /**
219
     * Test the object facade with an absolute object URL
220
     */
221
    public function testObjectFacadeAbsolute()
222
    {
223
        $object = Object::instance(getenv('APPARAT_BASE_URL').getenv('REPOSITORY_URL').self::OBJECT_PATH);
224
        $this->assertInstanceOf(Article::class, $object);
225
    }
226
227
    /**
228
     * Test the object facade with a relative object URL
229
     */
230
    public function testObjectFacadeRelative()
231
    {
232
        $object = Object::instance(getenv('REPOSITORY_URL').self::OBJECT_PATH);
233
        $this->assertInstanceOf(Article::class, $object);
234
        foreach ($object->getAuthors() as $author) {
235
            if ($author instanceof ApparatAuthor) {
236
//				echo $author->getId()->getId();
237
            }
238
        }
239
    }
240
241
    /**
242
     * Test the object facade with an invalid relative object URL
243
     *
244
     * @expectedException \Apparat\Resource\Infrastructure\Io\File\InvalidArgumentException
245
     * @expectedExceptionCode 1447616824
246
     */
247
    public function testObjectFacadeRelativeInvalid()
248
    {
249
        $object = Object::instance(getenv('REPOSITORY_URL').'/2015/12/21/2.article/2');
250
        $this->assertInstanceOf(Article::class, $object);
251
    }
252
253
    /**
254
     * Test with a missing object type class
255
     *
256
     * @expectedException \Apparat\Object\Application\Factory\InvalidArgumentException
257
     * @expectedExceptionCode 1450824842
258
     */
259
    public function testInvalidObjectTypeClass()
260
    {
261
        TestType::addInvalidType();
262
263
        $resource = $this->getMock(ResourceInterface::class);
264
        $resource->method('getPropertyData')->willReturn([SystemProperties::COLLECTION => ['type' => 'invalid']]);
265
        $articleObjectPath = new RepositoryPath(self::$repository, '/2016/02/16/5.invalid/5');
266
267
        /** @var ResourceInterface $resource */
268
        ObjectFactory::createFromResource($resource, $articleObjectPath);
269
    }
270
271
    /**
272
     * Test instantiation of object with invalid domain properties collection
273
     *
274
     * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
275
     * @expectedExceptionCode 1452288429
276
     */
277
    public function testInvalidDomainPropertyCollectionClass()
278
    {
279
        $this->getMockBuilder(AbstractObject::class)
280
            ->setConstructorArgs([new RepositoryPath(self::$repository, self::OBJECT_PATH)])
281
            ->getMock();
282
    }
283
284
    /**
285
     * Test the property data
286
     */
287
    public function testObjectPropertyData()
288
    {
289
//  $frontMarkResource = Resource::frontMark('file://'.__DIR__.DIRECTORY_SEPARATOR.'Fixture'.self::OBJECT_PATH.'.md');
290
        $object = Object::instance(getenv('REPOSITORY_URL').self::OBJECT_PATH);
291
        $this->assertTrue(is_array($object->getPropertyData()));
292
//        print_r($frontMarkResource->getData());
293
//        print_r($object->getPropertyData());
294
    }
295
296
    /**
297
     * Test the creation and persisting of an article object
298
     */
299
    public function testCreateArticleObject()
300
    {
301
        // Create a temporary repository
302
        $tempRepoDirectory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'temp-repo';
303
        $fileRepository = RepositoryFactory::create(
304
            getenv('REPOSITORY_URL'),
305
            [
306
                'type' => FileAdapterStrategy::TYPE,
307
                'root' => $tempRepoDirectory,
308
            ]
309
        );
310
        $this->assertInstanceOf(Repository::class, $fileRepository);
311
312
        // Create a new article in the temporary repository
313
        $payload = md5(rand());
314
        $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...
315
        $this->assertInstanceOf(Article::class, $article);
316
        $this->assertEquals($payload, $article->getPayload());
317
        $this->assertFileExists($tempRepoDirectory.
318
            str_replace('/', DIRECTORY_SEPARATOR, $article->getRepositoryPath()
319
                ->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))));
320
321
        // Delete temporary repository
322
        $this->deleteRecursive($tempRepoDirectory);
323
    }
324
325
    /**
326
     * Recursively register a directory and all nested files and directories for deletion on teardown
327
     *
328
     * @param string $directory Directory
329
     */
330
    protected function deleteRecursive($directory)
331
    {
332
        $this->tmpFiles[] = $directory;
333
        foreach (scandir($directory) as $item) {
334
            if (!preg_match('%^\.+$%', $item)) {
335
                $path = $directory.DIRECTORY_SEPARATOR.$item;
336
                if (is_dir($path)) {
337
                    $this->deleteRecursive($path);
338
                } else {
339
                    $this->tmpFiles[] = $path;
340
                }
341
            }
342
        }
343
    }
344
}
345