Completed
Push — master ( 61f16c...a373f3 )
by Joschi
03:28
created

ObjectTest   B

Complexity

Total Complexity 31

Size/Duplication

Total Lines 514
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 16

Importance

Changes 63
Bugs 2 Features 20
Metric Value
c 63
b 2
f 20
dl 0
loc 514
rs 8.2922
wmc 31
lcom 3
cbo 16

27 Methods

Rating   Name   Duplication   Size   Complexity  
A setUpBeforeClass() 0 11 1
A tearDown() 0 8 1
A testUndefinedObjectType() 0 11 1
A testInvalidObjectType() 0 9 1
A testLoadArticleObjectInvalidVisibility() 0 5 1
A testLoadNonExistingArticleObject() 0 16 1
A testLoadArticleObject() 0 15 1
A testLoadHiddenArticleObject() 0 7 1
A testLoadArticleObjectSystemProperties() 0 21 1
A testLoadArticleObjectMetaProperties() 0 18 1
A testLoadArticleObjectDomainProperties() 0 8 1
A testLoadArticleObjectDomainEmptyProperty() 0 6 1
A testObjectAbsolute() 0 5 1
A testObjectRelative() 0 5 1
A testObjectRelativeInvalid() 0 5 1
A testInvalidObjectTypeClass() 0 11 1
A testInvalidDomainPropertyCollectionClass() 0 6 1
A testObjectPropertyData() 0 9 1
B testMetaDataMutation() 0 25 1
A testRelationChange() 0 4 1
A testPersistEarlierRevision() 0 4 1
A testCreateArticleObjectLockingImpossible() 0 5 1
A testCreateAndPublishArticleObject() 0 69 2
A createRepositoryAndArticleObject() 0 18 1
A deleteRecursive() 0 15 4
A testDeleteArticleObjectImpossible() 0 8 1
A testUndeleteArticleObjectImpossible() 0 9 1
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\Kernel\Ports\Kernel;
40
    use Apparat\Object\Application\Factory\ObjectFactory;
41
    use Apparat\Object\Application\Model\Object\Article;
42
    use Apparat\Object\Application\Service\TypeService;
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\Properties\MetaProperties;
49
    use Apparat\Object\Domain\Model\Properties\SystemProperties;
50
    use Apparat\Object\Domain\Model\Uri\RepositoryLocator;
51
    use Apparat\Object\Domain\Repository\Repository;
52
    use Apparat\Object\Infrastructure\Factory\AdapterStrategyFactory;
53
    use Apparat\Object\Infrastructure\Model\Object\Object;
54
    use Apparat\Object\Infrastructure\Repository\FileAdapterStrategy;
55
    use Apparat\Object\Ports\Types\Object as ObjectTypes;
56
    use Apparat\Object\Infrastructure\Repository\Repository as InfrastructureRepository;
57
58
    /**
59
     * Object tests
60
     *
61
     * @package Apparat\Object
62
     * @subpackage Apparat\Object\Test
63
     */
64
    class ObjectTest extends AbstractRepositoryEnabledTest
65
    {
66
        /**
67
         * Example object locator
68
         *
69
         * @var string
70
         */
71
        const OBJECT_LOCATOR = '/2015/12/21/1-article/1';
72
        /**
73
         * Example hidden object locator
74
         *
75
         * @var string
76
         */
77
        const HIDDEN_OBJECT_LOCATOR = '/2016/05/26/6-article/6';
78
        /**
79
         * Default privacy
80
         *
81
         * @var string
82
         */
83
        protected static $defaultPrivacy;
84
85
        /**
86
         * Setup
87
         */
88
        public static function setUpBeforeClass()
89
        {
90
            parent::setUpBeforeClass();
91
            self::$defaultPrivacy = getenv('OBJECT_DEFAULT_PRIVACY');
92
93
            TypeService::enableType(Type::ARTICLE);
94
            TypeService::enableType(Type::CONTACT);
95
            TypeService::enableType(Type::GEO);
96
            TypeService::enableType(Type::IMAGE);
97
            TypeService::enableType(Type::NOTE);
98
        }
99
100
        /**
101
         * Tears down the fixture
102
         */
103
        public function tearDown()
104
        {
105
            putenv('MOCK_FLOCK');
106
            putenv('MOCK_RENAME');
107
            putenv('OBJECT_DEFAULT_PRIVACY='.self::$defaultPrivacy);
108
            TestTypeService::removeInvalidType();
109
            parent::tearDown();
110
        }
111
112
        /**
113
         * Test undefined object type
114
         *
115
         * @expectedException \Apparat\Object\Application\Factory\InvalidArgumentException
116
         * @expectedExceptionCode 1450905868
117
         */
118
        public function testUndefinedObjectType()
119
        {
120
            $resource = $this->createMock(ResourceInterface::class);
121
            $resource->method('getPropertyData')->willReturn([]);
122
            $repositoryLocator =
123
                $this->getMockBuilder(RepositoryLocator::class)->disableOriginalConstructor()->getMock();
124
125
            /** @var ResourceInterface $resource */
126
            /** @var RepositoryLocator $repositoryLocator */
127
            ObjectFactory::createFromResource($repositoryLocator, $resource);
128
        }
129
130
        /**
131
         * Test invalid object type
132
         *
133
         * @expectedException \Apparat\Object\Domain\Model\Object\InvalidArgumentException
134
         * @expectedExceptionCode 1449871242
135
         */
136
        public function testInvalidObjectType()
137
        {
138
            $resource = $this->createMock(ResourceInterface::class);
139
            $resource->method('getPropertyData')->willReturn([SystemProperties::COLLECTION => ['type' => 'invalid']]);
140
            $articleObjectLocator = new RepositoryLocator(self::$repository, self::OBJECT_LOCATOR);
141
142
            /** @var ResourceInterface $resource */
143
            ObjectFactory::createFromResource($articleObjectLocator, $resource);
144
        }
145
146
        /**
147
         * Load an article object with an invalid visibility requirement
148
         *
149
         * @expectedException \Apparat\Object\Domain\Repository\InvalidArgumentException
150
         * @expectedExceptionCode 1449999646
151
         */
152
        public function testLoadArticleObjectInvalidVisibility()
153
        {
154
            $articleObjectLocator = new RepositoryLocator(self::$repository, self::OBJECT_LOCATOR);
155
            self::$repository->loadObject($articleObjectLocator, 0);
156
        }
157
158
        /**
159
         * Load a non-existing article object
160
         *
161
         * @expectedException \Apparat\Object\Application\Model\Object\InvalidArgumentException
162
         * @expectedExceptionCode 1466882391
163
         */
164
        public function testLoadNonExistingArticleObject()
165
        {
166
            AdapterStrategyFactory::setAdapterStrategyTypeClass(
167
                TestFileAdapterStrategy::TYPE,
168
                TestFileAdapterStrategy::class
169
            );
170
            $repository = InfrastructureRepository::register(
171
                'non-'.getenv('REPOSITORY_URL'),
172
                [
173
                    'type' => TestFileAdapterStrategy::TYPE,
174
                    'root' => __DIR__.DIRECTORY_SEPARATOR.'Fixture',
175
                ]
176
            );
177
            $articleObjectLocator = new RepositoryLocator($repository, self::OBJECT_LOCATOR);
178
            $repository->loadObject($articleObjectLocator);
179
        }
180
181
        /**
182
         * Load an article object
183
         *
184
         * @expectedException \Apparat\Object\Domain\Model\Object\OutOfBoundsException
185
         * @expectedExceptionCode 1461619783
186
         */
187
        public function testLoadArticleObject()
188
        {
189
            $articleObjectLocator = new RepositoryLocator(self::$repository, self::OBJECT_LOCATOR);
190
            $articleObject = self::$repository->loadObject($articleObjectLocator);
191
            $this->assertEquals(
192
                getenv('APPARAT_BASE_URL').rtrim('/'.getenv('REPOSITORY_URL'), '/').self::OBJECT_LOCATOR,
193
                $articleObject->getAbsoluteUrl()
194
            );
195
            $this->assertFalse($articleObject->isDeleted());
196
            $this->assertFalse($articleObject->getRepositoryLocator()->isHidden());
197
198
            /** @var Revision $invalidRevision */
199
            $invalidRevision = Kernel::create(Revision::class, [99]);
200
            $articleObject->useRevision($invalidRevision);
201
        }
202
203
        /**
204
         * Load a hidden article object
205
         */
206
        public function testLoadHiddenArticleObject()
207
        {
208
            $articleObjectLocator = new RepositoryLocator(self::$repository, self::HIDDEN_OBJECT_LOCATOR);
209
            $articleObject = self::$repository->loadObject($articleObjectLocator);
210
            $this->assertTrue($articleObject->isDeleted());
211
            $this->assertTrue($articleObject->getRepositoryLocator()->isHidden());
212
        }
213
214
        /**
215
         * Load an article object and test its system properties
216
         */
217
        public function testLoadArticleObjectSystemProperties()
218
        {
219
            $articleObjectLocator = new RepositoryLocator(self::$repository, self::OBJECT_LOCATOR);
220
            $articleObject = self::$repository->loadObject($articleObjectLocator);
221
            $this->assertInstanceOf(Article::class, $articleObject);
222
            $this->assertEquals(new Id(1), $articleObject->getId());
223
            $this->assertEquals(Kernel::create(Type::class, [ObjectTypes::ARTICLE]), $articleObject->getType());
224
            $this->assertEquals(new Revision(1), $articleObject->getRevision());
225
            $this->assertFalse($articleObject->isDraft());
226
            $this->assertTrue($articleObject->isPublished());
227
            $this->assertEquals(new \DateTimeImmutable('2015-12-21T22:30:00'), $articleObject->getCreated());
228
            $this->assertEquals(new \DateTimeImmutable('2015-12-21T22:45:00'), $articleObject->getPublished());
229
            $this->assertNull($articleObject->getDeleted());
230
            $this->assertEquals('en', $articleObject->getLanguage());
231
            $this->assertEquals(
232
                "# Example article object\n\nThis file is an example for an object of type `\"article\"`. ".
233
                "It has a link to [Joschi Kuphal's website](https://jkphl.is) and features his avatar:\n".
234
                "![Joschi Kuphal](https://jkphl.is/avatar.jpg)",
235
                $articleObject->getPayload()
236
            );
237
        }
238
239
        /**
240
         * Load an article object and test its meta properties
241
         */
242
        public function testLoadArticleObjectMetaProperties()
243
        {
244
            $articleObjectLocator = new RepositoryLocator(self::$repository, self::OBJECT_LOCATOR);
245
            $articleObject = self::$repository->loadObject($articleObjectLocator);
246
            $this->assertInstanceOf(Article::class, $articleObject);
247
            $this->assertEquals('Example article object', $articleObject->getDescription());
248
            $this->assertEquals(
249
                'Article objects feature a Markdown payload along with some custom properties',
250
                $articleObject->getAbstract()
251
            );
252
            $this->assertArrayEquals(['apparat', 'object', 'example', 'article'], $articleObject->getKeywords());
253
            $this->assertArrayEquals(['example', 'text'], $articleObject->getCategories());
254
255
            // TODO Replace with contributed-by relations
256
//            $authorCount = count($articleObject->getAuthors());
257
//            $articleObject->addAuthor(AuthorFactory::createFromString(AuthorTest::GENERIC_AUTHOR));
258
//            $this->assertEquals($authorCount + 1, count($articleObject->getAuthors()));
259
        }
260
261
        /**
262
         * Load an article object and test its domain properties
263
         *
264
         * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
265
         * @expectedExceptionCode 1450818168
266
         */
267
        public function testLoadArticleObjectDomainProperties()
268
        {
269
            $articleObjectLocator = new RepositoryLocator(self::$repository, self::OBJECT_LOCATOR);
270
            $articleObject = self::$repository->loadObject($articleObjectLocator);
271
            $this->assertEquals('/system/url', $articleObject->getDomain('uid'));
272
            $this->assertEquals('value', $articleObject->getDomain('group:single'));
273
            $articleObject->getDomain('group:invalid');
274
        }
275
276
        /**
277
         * Load an article object and test an empty domain property name
278
         *
279
         * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
280
         * @expectedExceptionCode 1450817720
281
         */
282
        public function testLoadArticleObjectDomainEmptyProperty()
283
        {
284
            $articleObjectLocator = new RepositoryLocator(self::$repository, self::OBJECT_LOCATOR);
285
            $articleObject = self::$repository->loadObject($articleObjectLocator);
286
            $articleObject->getDomain('');
287
        }
288
289
        /**
290
         * Test the object facade with an absolute object URL
291
         */
292
        public function testObjectAbsolute()
293
        {
294
            $object = Object::load(getenv('APPARAT_BASE_URL').getenv('REPOSITORY_URL').self::OBJECT_LOCATOR);
295
            $this->assertInstanceOf(Article::class, $object);
296
        }
297
298
        /**
299
         * Test the object facade with a relative object URL
300
         */
301
        public function testObjectRelative()
302
        {
303
            $object = Object::load(getenv('REPOSITORY_URL').self::OBJECT_LOCATOR);
304
            $this->assertInstanceOf(Article::class, $object);
305
        }
306
307
        /**
308
         * Test the object facade with an invalid relative object URL
309
         *
310
         * @expectedException \Apparat\Resource\Ports\InvalidReaderArgumentException
311
         * @expectedExceptionCode 1447616824
312
         */
313
        public function testObjectRelativeInvalid()
314
        {
315
            $object = Object::load(getenv('REPOSITORY_URL').'/2015/12/21/2-article/2');
316
            $this->assertInstanceOf(Article::class, $object);
317
        }
318
319
        /**
320
         * Test with a missing object type class
321
         *
322
         * @expectedException \Apparat\Object\Application\Factory\InvalidArgumentException
323
         * @expectedExceptionCode 1450824842
324
         */
325
        public function testInvalidObjectTypeClass()
326
        {
327
            TestTypeService::addInvalidType();
328
329
            $resource = $this->createMock(ResourceInterface::class);
330
            $resource->method('getPropertyData')->willReturn([SystemProperties::COLLECTION => ['type' => 'invalid']]);
331
            $articleObjectLocator = new RepositoryLocator(self::$repository, '/2016/02/16/5-invalid/5');
332
333
            /** @var ResourceInterface $resource */
334
            ObjectFactory::createFromResource($articleObjectLocator, $resource);
335
        }
336
337
        /**
338
         * Test instantiation of object with invalid domain properties collection
339
         *
340
         * @expectedException \Apparat\Object\Domain\Model\Properties\InvalidArgumentException
341
         * @expectedExceptionCode 1452288429
342
         */
343
        public function testInvalidDomainPropertyCollectionClass()
344
        {
345
            $this->getMockBuilder(AbstractObject::class)
346
                ->setConstructorArgs([new RepositoryLocator(self::$repository, self::OBJECT_LOCATOR)])
347
                ->getMock();
348
        }
349
350
        /**
351
         * Test the property data
352
         */
353
        public function testObjectPropertyData()
354
        {
355
//            $frontMarkResource =
356
//                Resource::frontMark('file://'.__DIR__.DIRECTORY_SEPARATOR.'Fixture'.self::OBJECT_LOCATOR.'.md');
357
            $object = Object::load(getenv('REPOSITORY_URL').self::OBJECT_LOCATOR);
358
            $this->assertTrue(is_array($object->getPropertyData()));
359
//            print_r($frontMarkResource->getData());
360
//            print_r($object->getPropertyData());
361
        }
362
363
        /**
364
         * Test mutation by altering metadata
365
         *
366
         * @expectedException \Apparat\Object\Domain\Model\Properties\OutOfBoundsException
367
         * @expectedExceptionCode 1462632083
368
         */
369
        public function testMetaDataMutation()
370
        {
371
            $object = Object::load(getenv('REPOSITORY_URL').self::OBJECT_LOCATOR);
372
            $this->assertTrue(is_array($object->getPropertyData()));
373
            $objectUrl = $object->getAbsoluteUrl();
374
            $objectRevision = $object->getRevision();
375
            $object->setTitle($object->getTitle().' (mutated)');
376
            $object->setSlug($object->getSlug().'-mutated');
377
            $object->setDescription($object->getDescription().' (mutated)');
378
            $object->setAbstract($object->getAbstract());
379
            $object->setLicense(ltrim($object->getLicense().', ', ', ').'MIT');
380
            $object->setKeywords(array_merge($object->getKeywords(), ['mutated']));
381
            $object->setCategories($object->getCategories());
382
            $this->assertEquals(preg_replace('%\/(.?+)$%', '/.$1-2', $objectUrl), $object->getAbsoluteUrl());
383
            $this->assertEquals($objectRevision->getRevision() + 1, $object->getRevision()->getRevision());
384
            $this->assertTrue($object->hasBeenModified());
385
            $this->assertTrue($object->hasBeenMutated());
386
            $this->assertEquals('MIT', $object->getLicense());
387
            $this->assertEquals(ObjectTypes::PRIVACY_PRIVATE, $object->getPrivacy());
388
            $this->assertEquals(
389
                ObjectTypes::PRIVACY_PUBLIC,
390
                $object->setPrivacy(ObjectTypes::PRIVACY_PUBLIC)->getPrivacy()
391
            );
392
            $object->setPrivacy('invalid');
393
        }
394
395
        /**
396
         * Test change by altering relations
397
         */
398
        public function testRelationChange()
399
        {
400
            // TODO: Implement
401
        }
402
403
        /**
404
         * Test to persist an earlier revision
405
         */
406
        public function testPersistEarlierRevision()
407
        {
408
            // TODO
409
        }
410
411
        /**
412
         * Test the creation and persisting of an article object with failing file lock
413
         *
414
         * @expectedException \Apparat\Object\Domain\Repository\RuntimeException
415
         * @expectedExceptionCode 1461406873
416
         */
417
        public function testCreateArticleObjectLockingImpossible()
418
        {
419
            putenv('MOCK_FLOCK=1');
420
            $this->testCreateAndPublishArticleObject();
421
        }
422
423
        /**
424
         * Test the creation and persisting of an article object
425
         *
426
         * @expectedException \Apparat\Object\Domain\Model\Object\RuntimeException
427
         * @expectedExceptionCode 1462124874
428
         */
429
        public function testCreateAndPublishArticleObject()
430
        {
431
            putenv('OBJECT_DEFAULT_PRIVACY=public');
432
433
            // Create a temporary repository & article
434
            $tempRepoDirectory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'temp-repo';
435
            $payload = 'Revision 1 draft';
436
            $creationDate = new \DateTimeImmutable('yesterday');
437
            $article = $this->createRepositoryAndArticleObject($tempRepoDirectory, $payload, $creationDate);
438
            $this->assertInstanceOf(Article::class, $article);
439
            $this->assertEquals(MetaProperties::PRIVACY_PUBLIC, $article->getPrivacy());
440
            $this->assertEquals($payload, $article->getPayload());
441
            $this->assertFileExists($tempRepoDirectory.
442
                str_replace('/', DIRECTORY_SEPARATOR, $article->getRepositoryLocator()
443
                    ->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))));
444
            $this->assertEquals($creationDate, $article->getCreated());
445
446
            // Alter and persist the object
447
            $article->setPayload('Revision 1 draft (updated)');
448
            $article->persist();
449
450
            // Publish and persist the first object revision
451
            $article->setPayload('Revision 1');
452
            $article->publish();
453
            $article->persist();
454
455
            // Draft a second object revision
456
            $article->setPayload('Revision 2 draft');
457
            $article->persist();
458
459
            // Publish and persist the second object revision
460
            $article->publish();
461
            $article->setPayload('Revision 2');
462
            $article->persist();
463
464
            // Modify and persist a third object draft revision
465
            $article->setPayload('Revision 3 draft');
466
            $article->persist();
467
468
            // Wait for 2 seconds, modify and re-persist the object
469
            $now = time();
470
            sleep(2);
471
            $article->setPayload('Revision 3 draft (delayed modification)');
472
            $article->persist();
473
            $this->assertGreaterThanOrEqual($now + 2, $article->getModified()->format('U'));
474
475
            // Iterate through all object revisions
476
            foreach ($article as $articleRevisionIndex => $articleRevision) {
477
                $this->assertInstanceOf(Article::class, $articleRevision);
478
                $this->assertInstanceOf(Revision::class, $articleRevisionIndex);
479
            }
480
481
            // Publish and persist a third object draft revision
482
            $article->publish()->persist();
483
484
            // Delete the object (and all it's revisions)
485
            $article->delete()->persist();
486
487
            // Undelete the object (and all it's revisions)
488
            $article->undelete()->persist();
489
490
            // Use the first revision
491
            $article->rewind();
492
493
            // Delete temporary repository
494
            $this->deleteRecursive($tempRepoDirectory);
495
496
            $article->persist();
497
        }
498
499
        /**
500
         * Create a temporary repository and article object
501
         *
502
         * @param string $tempRepoDirectory Repository directory
503
         * @param string $payload Article payload
504
         * @param \DateTimeInterface $creationDate Article creation date
505
         * @return Article Article object
506
         */
507
        protected function createRepositoryAndArticleObject(
508
            $tempRepoDirectory,
509
            $payload,
510
            \DateTimeInterface $creationDate = null
511
        ) {
512
            $fileRepository = \Apparat\Object\Infrastructure\Repository\Repository::create(
513
                getenv('REPOSITORY_URL'),
514
                [
515
                    'type' => FileAdapterStrategy::TYPE,
516
                    'root' => $tempRepoDirectory,
517
                ]
518
            );
519
            $this->assertInstanceOf(Repository::class, $fileRepository);
520
            $this->assertEquals($fileRepository->getAdapterStrategy()->getRepositorySize(), 0);
521
522
            // Create a new article in the temporary repository
523
            return $fileRepository->createObject(ObjectTypes::ARTICLE, $payload, [], $creationDate);
524
        }
525
526
        /**
527
         * Recursively register a directory and all nested files and directories for deletion on teardown
528
         *
529
         * @param string $directory Directory
530
         */
531
        protected function deleteRecursive($directory)
532
        {
533
            $this->tmpFiles[] = $directory;
534
            foreach (scandir($directory) as $item) {
535
                if (!preg_match('%^\.+$%', $item)) {
536
                    $path = $directory.DIRECTORY_SEPARATOR.$item;
537
                    if (is_dir($path)) {
538
                        $this->deleteRecursive($path);
539
                        continue;
540
                    }
541
542
                    $this->tmpFiles[] = $path;
543
                }
544
            }
545
        }
546
547
        /**
548
         * Test the creation and persisting of an article object with failing file lock
549
         *
550
         * @expectedException \Apparat\Object\Infrastructure\Repository\RuntimeException
551
         * @expectedExceptionCode 1464269155
552
         */
553
        public function testDeleteArticleObjectImpossible()
554
        {
555
            putenv('MOCK_RENAME=1');
556
            $this->tmpFiles[] = $tempRepoDirectory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'temp-repo';
557
            $article = $this->createRepositoryAndArticleObject($tempRepoDirectory, 'Revision 1 draft');
558
            $this->deleteRecursive($tempRepoDirectory);
559
            $article->delete()->persist();
560
        }
561
562
        /**
563
         * Test the creation and persisting of an article object with failing file lock
564
         *
565
         * @expectedException \Apparat\Object\Infrastructure\Repository\RuntimeException
566
         * @expectedExceptionCode 1464269179
567
         */
568
        public function testUndeleteArticleObjectImpossible()
569
        {
570
            $this->tmpFiles[] = $tempRepoDirectory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'temp-repo';
571
            $article = $this->createRepositoryAndArticleObject($tempRepoDirectory, 'Revision 1 draft');
572
            $article->getRepositoryLocator()->getRepository()->deleteObject($article);
573
            $this->deleteRecursive($tempRepoDirectory);
574
            putenv('MOCK_RENAME=1');
575
            $article->undelete()->persist();
576
        }
577
    }
578
}
579
580
namespace Apparat\Object\Infrastructure\Repository {
581
582
    /**
583
     * Mocked version of the native flock() function
584
     *
585
     * @param resource $handle An open file pointer.
586
     * @param int $operation Operation is one of the following: LOCK_SH to acquire a shared lock (reader).
587
     * @param int $wouldblock The optional third argument is set to true if the lock would block (EWOULDBLOCK errno
588
     *     condition).
589
     * @return bool True on success or False on failure.
590
     */
591
    function flock($handle, $operation, &$wouldblock = null)
592
    {
593
        return (getenv('MOCK_FLOCK') != 1) ? \flock($handle, $operation, $wouldblock) : false;
594
    }
595
596
    /**
597
     * Mocked version of the native rename() function
598
     *
599
     * @param string $oldname The old name. The wrapper used in oldname must match the wrapper used in newname.
600
     * @param string $newname The new name.
601
     * @return bool true on success or false on failure.
602
     */
603
    function rename($oldname, $newname)
604
    {
605
        return (getenv('MOCK_RENAME') != 1) ? \rename($oldname, $newname) : false;
606
    }
607
}
608