10000 feature #28931 [PhpUnitBridge] Added ClassExistsMock (ro0NL) · symfony/symfony@a9694f7 · GitHub
[go: up one dir, main page]

Skip to content

Commit a9694f7

Browse files
committed
feature #28931 [PhpUnitBridge] Added ClassExistsMock (ro0NL)
This PR was squashed before being merged into the 4.3-dev branch (closes #28931). Discussion ---------- [PhpUnitBridge] Added ClassExistsMock | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #... <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | symfony/symfony-docs#10528 I've thought about this before, and bumped into it again when trying to test #28898 This PR allows to mock `class|interface|trait_exists` to enable specific code path testing Commits ------- 62caec1 [PhpUnitBridge] Added ClassExistsMock
2 parents 7dc1521 + 62caec1 commit a9694f7

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed

src/Symfony/Bridge/PhpUnit/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
4.3.0
5+
-----
6+
7+
* added `ClassExistsMock`
8+
49
4.1.0
510
-----
611

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\PhpUnit;
13+
14+
/**
15+
* @author Roland Franssen <franssen.roland@gmail.com>
16+
*/
17+
class ClassExistsMock
18+
{
19+
private static $classes = array();
20+
21+
/**
22+
* Configures the classes to be checked upon existence.
23+
*
24+
* @param array $classes Mocked class names as keys (case sensitive, without leading root namespace slash) and booleans as values
25+
*/
26+
public static function withMockedClasses(array $classes)
27+
{
28+
self::$classes = $classes;
29+
}
30+
31+
public static function class_exists($name, $autoload = true)
32+
{
33+
return (bool) (self::$classes[ltrim($name, '\\')] ?? \class_exists($name, $autoload));
34+
}
35+
36+
public static function interface_exists($name, $autoload = true)
37+
{
38+
return (bool) (self::$classes[ltrim($name, '\\')] ?? \interface_exists($name, $autoload));
39+
}
40+
41+
public static function trait_exists($name, $autoload = true)
42+
{
43+
return (bool) (self::$classes[ltrim($name, '\\')] ?? \trait_exists($name, $autoload));
44+
}
45+
46+
public static function register($class)
47+
{
48+
$self = \get_called_class();
49+
50+
$mockedNs = array(substr($class, 0, strrpos($class, '\\')));
51+
if (0 < strpos($class, '\\Tests\\')) {
52+
$ns = str_replace('\\Tests\\', '\\', $class);
53+
$mockedNs[] = substr($ns, 0, strrpos($ns, '\\'));
54+
} elseif (0 === strpos($class, 'Tests\\')) {
55+
$mockedNs[] = substr($class, 6, strrpos($class, '\\') - 6);
56+
}
57+
foreach ($mockedNs as $ns) {
58+
foreach (array('class', 'interface', 'trait') as $type) {
59+
if (\function_exists($ns.'\\'.$type.'_exists')) {
60+
continue;
61+
}
62+
eval(<<<EOPHP
63+
namespace $ns;
64+
65+
function {$type}_exists(\$name, \$autoload = true)
66+
{
67+
return \\$self::{$type}_exists(\$name, \$autoload);
68+
}
69+
70+
EOPHP
71+
);
72+
}
73+
}
74+
}
75+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\PhpUnit\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ClassExistsMock;
16+
17+
class ClassExistsMockTest extends TestCase
18+
{
19+
public static function setUpBeforeClass()
20+
{
21+
ClassExistsMock::register(__CLASS__);
22+
}
23+
24+
protected function setUp()
25+
{
26+
ClassExistsMock::withMockedClasses(array(
27+
ExistingClass::class => false,
28+
'NonExistingClass' => true,
29+
ExistingInterface::class => false,
30+
'NonExistingInterface' => true,
31+
ExistingTrait::class => false,
32+
'NonExistingTrait' => true,
33+
));
34+
}
35+
36+
public function testClassExists()
37+
{
38+
$this->assertFalse(class_exists(ExistingClass::class));
39+
$this->assertFalse(class_exists(ExistingClass::class, false));
40+
$this->assertFalse(class_exists('\\'.ExistingClass::class));
41+
$this->assertFalse(class_exists('\\'.ExistingClass::class, false));
42+
$this->assertTrue(class_exists('NonExistingClass'));
43+
$this->assertTrue(class_exists('NonExistingClass', false));
44+
$this->assertTrue(class_exists('\\NonExistingClass'));
45+
$this->assertTrue(class_exists('\\NonExistingClass', false));
46+
$this->assertTrue(class_exists(ExistingClassReal::class));
47+
$this->assertTrue(class_exists(ExistingClassReal::class, false));
48+
$this->assertTrue(class_exists('\\'.ExistingClassReal::class));
49+
$this->assertTrue(class_exists('\\'.ExistingClassReal::class, false));
50+
$this->assertFalse(class_exists('NonExistingClassReal'));
51+
$this->assertFalse(class_exists('NonExistingClassReal', false));
52+
$this->assertFalse(class_exists('\\NonExistingClassReal'));
53+
$this->assertFalse(class_exists('\\NonExistingClassReal', false));
54+
}
55+
56+
public function testInterfaceExists()
57+
{
58+
$this->assertFalse(interface_exists(ExistingInterface::class));
59+
$this->assertFalse(interface_exists(ExistingInterface::class, false));
60+
$this->assertFalse(interface_exists('\\'.ExistingInterface::class));
61+
$this->assertFalse(interface_exists('\\'.ExistingInterface::class, false));
62+
$this->assertTrue(interface_exists('NonExistingInterface'));
63+
$this->assertTrue(interface_exists('NonExistingInterface', false));
64+
$this->assertTrue(interface_exists('\\NonExistingInterface'));
65+
$this->assertTrue(interface_exists('\\NonExistingInterface', false));
66+
$this->assertTrue(interface_exists(ExistingInterfaceReal::class));
67+
$this->assertTrue(interface_exists(ExistingInterfaceReal::class, false));
68+
$this->assertTrue(interface_exists('\\'.ExistingInterfaceReal::class));
69+
$this->assertTrue(interface_exists('\\'.ExistingInterfaceReal::class, false));
70+
$this->assertFalse(interface_exists('NonExistingClassReal'));
71+
$this->assertFalse(interface_exists('NonExistingClassReal', false));
72+
$this->assertFalse(interface_exists('\\NonExistingInterfaceReal'));
73+
$this->assertFalse(interface_exists('\\NonExistingInterfaceReal', false));
74+
}
75+
76+
public function testTraitExists()
77+
{
78+
$this->assertFalse(trait_exists(ExistingTrait::class));
79+
$this->assertFalse(trait_exists(ExistingTrait::class, false));
80+
$this->assertFalse(trait_exists('\\'.ExistingTrait::class));
81+
$this->assertFalse(trait_exists('\\'.ExistingTrait::class, false));
82+
$this->assertTrue(trait_exists('NonExistingTrait'));
83+
$this->assertTrue(trait_exists('NonExistingTrait', false));
84+
$this->assertTrue(trait_exists('\\NonExistingTrait'));
85+
$this->assertTrue(trait_exists('\\NonExistingTrait', false));
86+
$this->assertTrue(trait_exists(ExistingTraitReal::class));
87+
$this->assertTrue(trait_exists(ExistingTraitReal::class, false));
88+
$this->assertTrue(trait_exists('\\'.ExistingTraitReal::class));
89+
$this->assertTrue(trait_exists('\\'.ExistingTraitReal::class, false));
90+
$this->assertFalse(trait_exists('NonExistingClassReal'));
91+
$this->assertFalse(trait_exists('NonExistingClassReal', false));
92+
$this->assertFalse(trait_exists('\\NonExistingTraitReal'));
93+
$this->assertFalse(trait_exists('\\NonExistingTraitReal', false));
94+
}
95+
}
96+
97+
class ExistingClass
98+
{
99+
}
100+
101+
class ExistingClassReal
102+
{
103+
}
104+
105+
interface ExistingInterface
106+
{
107+
}
108+
109+
interface ExistingInterfaceReal
110+
{
111+
}
112+
113+
trait ExistingTrait
114+
{
115+
}
116+
117+
trait ExistingTraitReal
118+
{
119+
}

0 commit comments

Comments
 (0)
0