Skip to content

Commit 5417cb9

Browse files
committed
Added additional tests for 100% MSI.
1 parent 66ba710 commit 5417cb9

File tree

12 files changed

+173
-13
lines changed

12 files changed

+173
-13
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace ScriptFUSION\Porter;
5+
6+
/**
7+
* The exception that is thrown when a class does not implement the __clone method.
8+
*/
9+
final class CloneNotImplementedException extends \LogicException
10+
{
11+
// Intentionally empty.
12+
}

src/Porter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ private function fetch(ImportSpecification $specification): \Iterator
122122
/* __clone method cannot be specified in interface due to Mockery limitation.
123123
See https://github.com/mockery/mockery/issues/669 */
124124
if ($connector instanceof ConnectorOptions && !method_exists($connector, '__clone')) {
125-
throw new \LogicException(
125+
throw new CloneNotImplementedException(
126126
'Connector with options must implement __clone() method to deep clone options.'
127127
);
128128
}
@@ -201,7 +201,7 @@ private function fetchAsync(AsyncImportSpecification $specification): Iterator
201201
/* __clone method cannot be specified in interface due to Mockery limitation.
202202
See https://github.com/mockery/mockery/issues/669 */
203203
if ($connector instanceof ConnectorOptions && !method_exists($connector, '__clone')) {
204-
throw new \LogicException(
204+
throw new CloneNotImplementedException(
205205
'Connector with options must implement __clone() method to deep clone options.'
206206
);
207207
}

src/PorterAwareTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ trait PorterAwareTrait
88
/** @var Porter */
99
private $porter;
1010

11-
protected function getPorter(): Porter
11+
private function getPorter(): Porter
1212
{
1313
return $this->porter;
1414
}

src/Specification/Specification.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
use ScriptFUSION\Porter\Connector\Recoverable\RecoverableExceptionHandler;
77
use ScriptFUSION\Porter\Transform\AnysyncTransformer;
8-
use ScriptFUSION\Porter\Transform\Transformer;
98

109
abstract class Specification
1110
{
@@ -58,7 +57,7 @@ static function (AnysyncTransformer $transformer): AnysyncTransformer {
5857

5958
\is_object($this->context) && $this->context = clone $this->context;
6059
$this->recoverableExceptionHandler &&
61-
$this->recoverableExceptionHandler = clone $this->recoverableExceptionHandler;
60+
$this->recoverableExceptionHandler = clone $this->recoverableExceptionHandler;
6261
}
6362

6463
/**
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace ScriptFUSIONTest\Integration\Collection;
5+
6+
use Amp\Iterator;
7+
use PHPUnit\Framework\TestCase;
8+
use ScriptFUSION\Porter\Collection\AsyncFilteredRecords;
9+
use ScriptFUSION\Porter\Collection\AsyncPorterRecords;
10+
use ScriptFUSION\Porter\Collection\AsyncProviderRecords;
11+
use ScriptFUSION\Porter\Collection\AsyncRecordCollection;
12+
use ScriptFUSION\Porter\Provider\Resource\AsyncResource;
13+
use ScriptFUSION\Porter\Specification\AsyncImportSpecification;
14+
15+
/**
16+
* @see AsyncRecordCollection
17+
*/
18+
final class AsyncRecordCollectionTest extends TestCase
19+
{
20+
public function testGetPreviousCollection(): void
21+
{
22+
$records = new AsyncPorterRecords(
23+
$previous = \Mockery::mock(AsyncRecordCollection::class),
24+
\Mockery::mock(AsyncImportSpecification::class)
25+
);
26+
27+
self::assertSame($previous, $records->getPreviousCollection());
28+
}
29+
30+
/**
31+
* Tests that for each member in a stack of AsyncRecordCollections, the first collection always points to the
32+
* innermost collection.
33+
*/
34+
public function testFindFirstCollection(): void
35+
{
36+
$collection3 = new AsyncFilteredRecords(
37+
$iterator = \Mockery::mock(Iterator::class),
38+
$collection2 = new AsyncPorterRecords(
39+
$collection1 =
40+
new AsyncProviderRecords($iterator, \Mockery::mock(AsyncResource::class)),
41+
\Mockery::mock(AsyncImportSpecification::class)
42+
),
43+
[$this, __FUNCTION__]
44+
);
45+
46+
self::assertSame($collection1, $collection1->findFirstCollection());
47+
self::assertSame($collection1, $collection2->findFirstCollection());
48+
self::assertSame($collection1, $collection3->findFirstCollection());
49+
}
50+
}

test/Integration/Connector/CachingConnectorTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,38 @@ public function testCacheUsedForDifferentOptionsInstance(): void
9191
self::assertSame('bar', $this->connector->fetch('baz'));
9292
}
9393

94+
/**
95+
* Tests that when the same options are specified in a different order, the cache is reused.
96+
*/
97+
public function testCacheUsedForOptionsInDifferentOrder(): void
98+
{
99+
$o1 = new class extends EncapsulatedOptions {
100+
public function __construct()
101+
{
102+
$this->setDefaults([
103+
'Alfa' => 'Alfa',
104+
'Bravo' => 'Bravo',
105+
]);
106+
}
107+
};
108+
109+
$o2 = new class extends EncapsulatedOptions {
110+
public function __construct()
111+
{
112+
$this->setDefaults([
113+
'Bravo' => 'Bravo',
114+
'Alfa' => 'Alfa',
115+
]);
116+
}
117+
};
118+
119+
$this->wrappedConnector->shouldReceive('getOptions')->andReturn($o1, $o2);
120+
121+
self::assertNotSame($o1->copy(), $o2->copy(), 'Options render differently.');
122+
self::assertSame('foo', $this->connector->fetch('bar'));
123+
self::assertSame('foo', $this->connector->fetch('bar'));
124+
}
125+
94126
public function testNullAndEmptyOptionsAreEquivalent(): void
95127
{
96128
/** @var EncapsulatedOptions $options */

test/Integration/PorterAsyncTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Amp\Iterator;
77
use Amp\Loop;
88
use Amp\Producer;
9+
use ScriptFUSION\Porter\CloneNotImplementedException;
910
use ScriptFUSION\Porter\Collection\AsyncRecordCollection;
1011
use ScriptFUSION\Porter\Collection\CountableAsyncPorterRecords;
1112
use ScriptFUSION\Porter\Collection\CountableAsyncProviderRecords;
@@ -96,6 +97,7 @@ public function testImportIncompatibleProviderAsync(): \Generator
9697
$this->registerProvider(\Mockery::mock(Provider::class), $providerName = 'foo');
9798

9899
$this->expectException(IncompatibleProviderException::class);
100+
$this->expectExceptionMessageRegExp('[\bAsyncProvider\b]');
99101
yield $this->porter->importAsync($this->specification->setProviderName($providerName));
100102
}
101103

@@ -119,7 +121,7 @@ public function testImportAsyncConnectorWithOptions(): void
119121
$this->provider->shouldReceive('getAsyncConnector')
120122
->andReturn(\Mockery::mock(AsyncConnector::class, ConnectorOptions::class));
121123

122-
$this->expectException(\LogicException::class);
124+
$this->expectException(CloneNotImplementedException::class);
123125
$this->porter->importAsync($this->specification);
124126
}
125127

test/Integration/PorterSyncTest.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace ScriptFUSIONTest\Integration;
55

66
use ScriptFUSION\Porter\Cache\CacheUnavailableException;
7+
use ScriptFUSION\Porter\CloneNotImplementedException;
78
use ScriptFUSION\Porter\Collection\CountablePorterRecords;
89
use ScriptFUSION\Porter\Collection\FilteredRecords;
910
use ScriptFUSION\Porter\Collection\PorterRecords;
@@ -90,10 +91,28 @@ public function testImportConnectorWithOptions(): void
9091
$this->provider->shouldReceive('getConnector')
9192
->andReturn(\Mockery::mock(Connector::class, ConnectorOptions::class));
9293

93-
$this->expectException(\LogicException::class);
94+
$this->expectException(CloneNotImplementedException::class);
9495
$this->porter->import($this->specification);
9596
}
9697

98+
/**
99+
* Tests that when importing multiple records, records may be rewound when the iterator supports this.
100+
*/
101+
public function testRewind(): void
102+
{
103+
$this->resource->shouldReceive('fetch')->andReturn(new \ArrayIterator([$i1 = ['foo'], $i2 = ['bar']]));
104+
105+
$records = $this->porter->import($this->specification);
106+
107+
self::assertTrue($records->valid());
108+
self::assertCount(2, $records);
109+
self::assertSame($i1, $records->current());
110+
$records->next();
111+
self::assertSame($i2, $records->current());
112+
$records->rewind();
113+
self::assertSame($i1, $records->current());
114+
}
115+
97116
/**
98117
* Tests that when a Transformer is PorterAware it receives the Porter instance that invoked it.
99118
*/
@@ -146,8 +165,10 @@ public function testImportFailure(): void
146165
public function testImportUnregisteredProvider(): void
147166
{
148167
$this->expectException(ProviderNotFoundException::class);
168+
$this->expectExceptionMessage($providerName = 'foo');
169+
$this->expectExceptionCode(0);
149170

150-
$this->porter->import($this->specification->setProviderName('foo'));
171+
$this->porter->import($this->specification->setProviderName("\"$providerName\""));
151172
}
152173

153174
/**
@@ -158,6 +179,7 @@ public function testImportIncompatibleProvider(): void
158179
$this->registerProvider(\Mockery::mock(AsyncProvider::class), $providerName = 'foo');
159180

160181
$this->expectException(IncompatibleProviderException::class);
182+
$this->expectExceptionMessageRegExp('[\bProvider\b]');
161183
$this->porter->import($this->specification->setProviderName($providerName));
162184
}
163185

test/Unit/AsyncImportSpecificationTest.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
use PHPUnit\Framework\TestCase;
77
use ScriptFUSION\Porter\Connector\Recoverable\ExponentialAsyncDelayRecoverableExceptionHandler;
8+
use ScriptFUSION\Porter\Connector\Recoverable\RecoverableExceptionHandler;
89
use ScriptFUSION\Porter\Provider\Resource\AsyncResource;
910
use ScriptFUSION\Porter\Specification\AsyncImportSpecification;
1011
use ScriptFUSION\Porter\Specification\IncompatibleTransformerException;
@@ -19,9 +20,12 @@ final class AsyncImportSpecificationTest extends TestCase
1920
/** @var AsyncImportSpecification */
2021
private $specification;
2122

23+
/** @var AsyncResource */
24+
private $resource;
25+
2226
protected function setUp(): void
2327
{
24-
$this->specification = new AsyncImportSpecification(\Mockery::mock(AsyncResource::class));
28+
$this->specification = new AsyncImportSpecification($this->resource = \Mockery::mock(AsyncResource::class));
2529
}
2630

2731
/**
@@ -46,4 +50,32 @@ public function testDefaultExceptionHandler(): void
4650
$this->specification->getRecoverableExceptionHandler()
4751
);
4852
}
53+
54+
public function testClone(): void
55+
{
56+
$this->specification
57+
->addTransformer(\Mockery::mock(AsyncTransformer::class))
58+
->setContext($context = new class {
59+
// Intentionally empty.
60+
})
61+
->setRecoverableExceptionHandler($handler = \Mockery::mock(RecoverableExceptionHandler::class))
62+
;
63+
64+
$specification = clone $this->specification;
65+
66+
self::assertNotSame($this->resource, $specification->getAsyncResource());
67+
68+
self::assertNotSame(
69+
array_values($this->specification->getTransformers()),
70+
array_values($specification->getTransformers())
71+
);
72+
self::assertNotSame(
73+
array_keys($this->specification->getTransformers()),
74+
array_keys($specification->getTransformers())
75+
);
76+
self::assertCount(\count($this->specification->getTransformers()), $specification->getTransformers());
77+
78+
self::assertNotSame($context, $specification->getContext());
79+
self::assertNotSame($handler, $specification->getRecoverableExceptionHandler());
80+
}
4981
}

test/Unit/Collection/RecordCollectionTest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ final class RecordCollectionTest extends TestCase
1414
{
1515
use MockeryPHPUnitIntegration;
1616

17-
public function testFindParent(): void
17+
/**
18+
* Tests that for each member in a stack of RecordCollections, the first collection always points to the
19+
* innermost collection.
20+
*/
21+
public function testFindFirstCollection(): void
1822
{
1923
/**
2024
* @var RecordCollection $collection1

0 commit comments

Comments
 (0)