Skip to content

Commit 99d75ff

Browse files
committed
Add Utils\Target
1 parent c32ea12 commit 99d75ff

2 files changed

Lines changed: 235 additions & 0 deletions

File tree

src/Utils/Target.php

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
/**
3+
* CROSS PHPunit Utils
4+
*
5+
* @filesource
6+
* @copyright 2019 Cross Solution <https://www.cross-solution.de>
7+
* @license MIT
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace Cross\TestUtils\Utils;
13+
14+
/**
15+
*
16+
* @author Mathias Gelhausen <gelhausen@cross-solution.de>
17+
* @todo write tests
18+
*/
19+
final class Target
20+
{
21+
22+
public static function get(
23+
object $testcase,
24+
array $methods,
25+
array $properties,
26+
?string $classesProperty = null,
27+
bool $forceObject = false
28+
) {
29+
$testcaseReflection = new \ReflectionClass($testcase);
30+
31+
foreach ($methods as $method) {
32+
if ($testcaseReflection->hasMethod($method)) {
33+
$testcaseMethod = $testcaseReflection->getMethod($method);
34+
$testcaseMethod->setAccessible(true);
35+
36+
return self::create($testcaseMethod->invoke($testcase), $forceObject);
37+
}
38+
}
39+
40+
foreach ($properties as $property) {
41+
if ($testcaseReflection->hasProperty($property)) {
42+
$testcaseProperty = $testcaseReflection->getProperty($property);
43+
$testcaseProperty->setAccessible(true);
44+
45+
return self::create($testcaseProperty->getValue($testcase), $forceObject);
46+
}
47+
}
48+
49+
if ($classesProperty
50+
&& $testcaseReflection->hasProperty($classesProperty)
51+
) {
52+
$testcaseProperty = $testcaseReflection->getProperty($classesProperty);
53+
$testcaseProperty->setAccessible(true);
54+
55+
$propertyValue = $testcaseProperty->getValue($testcase);
56+
57+
if (is_array($propertyValue) && count($propertyValue)) {
58+
if (isset($propertyValue['target'])) {
59+
$target = self::create($propertyValue['target'], $forceObject);
60+
unset($propertyValue['target']);
61+
} else {
62+
$target = self::create(array_shift($propertyValue), $forceObject);
63+
}
64+
65+
$testcaseProperty->setValue($testcase, $propertyValue);
66+
67+
return $target;
68+
}
69+
}
70+
71+
throw new \PHPUnit_Framework_Exception('Could not find or create a target instance.');
72+
}
73+
74+
/**
75+
* Creates an instance or returns FQCN
76+
*
77+
* @param string|array $spec
78+
* @param bool $forceObject
79+
* @return string|object
80+
*/
81+
private static function create($spec, bool $forceObject)
82+
{
83+
if (is_array($spec)) {
84+
$class = array_shift($spec);
85+
return new $class(...$spec);
86+
}
87+
88+
if (is_string($spec)) {
89+
if (0 === strpos($spec, '!')) {
90+
return new \ReflectionClass(substr($spec, 1));
91+
}
92+
93+
if ($forceObject) {
94+
return new $spec();
95+
}
96+
}
97+
98+
return $spec;
99+
}
100+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
/**
3+
* CROSS PHPunit Utils
4+
*
5+
* @filesource
6+
* @copyright 2019 Cross Solution <https://www.cross-solution.de>
7+
* @license MIT
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace Cross\TestUtilsTest\Utils;
13+
14+
use Cross\TestUtils\Utils\Target;
15+
16+
/**
17+
* Tests for \Cross\TestUtils\Utils\Target
18+
*
19+
* @covers \Cross\TestUtils\Utils\Target
20+
* @author Mathias Gelhausen <gelhausen@cross-solution.de>
21+
*
22+
* @group Cross.TestUtils
23+
* @group Cross.TestUtils.Utils
24+
* @group Cross.TestUtils.Utils.Target
25+
*/
26+
class TargetTest extends \PHPUnit_Framework_TestCase
27+
{
28+
29+
public function testGetTargetInstanceFromMethod()
30+
{
31+
$target = new class
32+
{
33+
public function getTestTarget() { return 'TestTarget'; }
34+
};
35+
36+
$actual = Target::get($target, ['getTestTarget'], ['testTarget']);
37+
38+
static::assertEquals('TestTarget', $actual);
39+
}
40+
41+
public function testGetTargetInstanceFromProperty()
42+
{
43+
$target = new class
44+
{
45+
public $testTarget = 'TestTarget';
46+
};
47+
48+
$actual = Target::get($target, ['getTestTarget'], ['testTarget']);
49+
50+
static::assertEquals('TestTarget', $actual);
51+
}
52+
53+
public function testGetTargetInstanceFromClassesPropertyTargetKey()
54+
{
55+
$target = new class
56+
{
57+
public $classes = ['target' => 'TestTarget', 'other', 'values'];
58+
};
59+
60+
$actual = Target::get($target, [], [], 'classes');
61+
62+
static::assertEquals('TestTarget', $actual);
63+
static::assertEquals( ['other', 'values'], $target->classes, 'Target specification was not unset!');
64+
}
65+
66+
public function testGetTargetInstanceFromClassesPropertyFirstItem()
67+
{
68+
$target = new class
69+
{
70+
public $classes = ['TestTarget', 'other', 'values'];
71+
public function test()
72+
{
73+
return $this->getTargetInstance([], [], 'classes');
74+
}
75+
};
76+
77+
$actual = Target::get($target, [], [], 'classes');
78+
79+
static::assertEquals('TestTarget', $actual);
80+
static::assertEquals( ['other', 'values'], $target->classes, 'Target specification was not unset!');
81+
}
82+
83+
public function testExceptionIsThrownIfNoTargetWasFound()
84+
{
85+
$target = new class {};
86+
87+
$this->expectException(\PHPUnit_Framework_Exception::class);
88+
$this->expectExceptionMessage('find or create');
89+
90+
Target::get($target, [], []);
91+
}
92+
93+
public function testGetTargetInstanceReflection()
94+
{
95+
$target = new class
96+
{
97+
public $testTarget = '!\stdClass';
98+
};
99+
100+
$actual = Target::get($target, ['getTestTarget'], ['testTarget']);
101+
102+
static::assertInstanceOf(\ReflectionClass::class, $actual);
103+
}
104+
105+
public function testGetTargetInstanceFromArraySpec()
106+
{
107+
$classObj = new class('') { public $arg; public function __construct($arg) { $this->arg = $arg;}};
108+
$class = get_class($classObj);
109+
110+
$target = new class($class)
111+
{
112+
public $class;
113+
public function getTestTarget() { return [$this->class, 'arg']; }
114+
public function __construct($class) {
115+
$this->class = $class;
116+
}
117+
};
118+
119+
$actual = Target::get($target, ['getTestTarget'], ['testTarget']);
120+
121+
static::assertInstanceOf($class, $actual);
122+
}
123+
124+
public function testGetTargetInstanceForcedObject()
125+
{
126+
$target = new class
127+
{
128+
public $testTarget = \stdClass::class;
129+
};
130+
131+
$actual = Target::get($target, ['getTestTarget'], ['testTarget'], '', true);
132+
133+
static::assertInstanceOf(\stdClass::class, $actual);
134+
}
135+
}

0 commit comments

Comments
 (0)