Skip to content

Commit 130cc26

Browse files
committed
[PhpUnitBridge] Enable configuring mock ns with attributes
1 parent bbe1b6e commit 130cc26

17 files changed

+537
-11
lines changed

.github/workflows/phpunit-bridge.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ jobs:
3535
php-version: "7.2"
3636

3737
- name: Lint
38-
run: find ./src/Symfony/Bridge/PhpUnit -name '*.php' | grep -v -e /Tests/ -e ForV7 -e ForV8 -e ForV9 -e ConstraintLogicTrait | parallel -j 4 php -l {}
38+
run: find ./src/Symfony/Bridge/PhpUnit -name '*.php' | grep -v -e /Tests/ -e /Attribute/ -e /Extension/ -e /Metadata/ -e ForV7 -e ForV8 -e ForV9 -e ConstraintLogicTrait | parallel -j 4 php -l {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\Attribute;
13+
14+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
15+
final class DnsSensitive
16+
{
17+
public function __construct(
18+
public readonly ?string $class = null,
19+
) {
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\Attribute;
13+
14+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
15+
final class TimeSensitive
16+
{
17+
public function __construct(
18+
public readonly ?string $class = null,
19+
) {
20+
}
21+
}

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+
7.3
5+
---
6+
7+
* Enable configuring clock and DNS mock namespaces with attributes
8+
49
7.2
510
---
611

src/Symfony/Bridge/PhpUnit/Extension/DisableClockMockSubscriber.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@
1515
use PHPUnit\Event\Test\Finished;
1616
use PHPUnit\Event\Test\FinishedSubscriber;
1717
use PHPUnit\Metadata\Group;
18+
use Symfony\Bridge\PhpUnit\Attribute\TimeSensitive;
1819
use Symfony\Bridge\PhpUnit\ClockMock;
20+
use Symfony\Bridge\PhpUnit\Metadata\AttributeReader;
1921

2022
/**
2123
* @internal
2224
*/
2325
class DisableClockMockSubscriber implements FinishedSubscriber
2426
{
27+
public function __construct(
28+
private AttributeReader $reader,
29+
) {
30+
}
31+
2532
public function notify(Finished $event): void
2633
{
2734
$test = $event->test();
@@ -33,7 +40,12 @@ public function notify(Finished $event): void
3340
foreach ($test->metadata() as $metadata) {
3441
if ($metadata instanceof Group && 'time-sensitive' === $metadata->groupName()) {
3542
ClockMock::withClockMock(false);
43+
break;
3644
}
3745
}
46+
47+
if ($this->reader->forClassAndMethod($test->className(), $test->methodName(), TimeSensitive::class)) {
48+
ClockMock::withClockMock(false);
49+
}
3850
}
3951
}

src/Symfony/Bridge/PhpUnit/Extension/DisableDnsMockSubscriber.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@
1515
use PHPUnit\Event\Test\Finished;
1616
use PHPUnit\Event\Test\FinishedSubscriber;
1717
use PHPUnit\Metadata\Group;
18+
use Symfony\Bridge\PhpUnit\Attribute\DnsSensitive;
1819
use Symfony\Bridge\PhpUnit\DnsMock;
20+
use Symfony\Bridge\PhpUnit\Metadata\AttributeReader;
1921

2022
/**
2123
* @internal
2224
*/
2325
class DisableDnsMockSubscriber implements FinishedSubscriber
2426
{
27+
public function __construct(
28+
private AttributeReader $reader,
29+
) {
30+
}
31+
2532
public function notify(Finished $event): void
2633
{
2734
$test = $event->test();
@@ -33,7 +40,12 @@ public function notify(Finished $event): void
3340
foreach ($test->metadata() as $metadata) {
3441
if ($metadata instanceof Group && 'dns-sensitive' === $metadata->groupName()) {
3542
DnsMock::withMockedHosts([]);
43+
break;
3644
}
3745
}
46+
47+
if ($this->reader->forClassAndMethod($test->className(), $test->methodName(), DnsSensitive::class)) {
48+
DnsMock::withMockedHosts([]);
49+
}
3850
}
3951
}

src/Symfony/Bridge/PhpUnit/Extension/EnableClockMockSubscriber.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@
1515
use PHPUnit\Event\Test\PreparationStarted;
1616
use PHPUnit\Event\Test\PreparationStartedSubscriber;
1717
use PHPUnit\Metadata\Group;
18+
use Symfony\Bridge\PhpUnit\Attribute\TimeSensitive;
1819
use Symfony\Bridge\PhpUnit\ClockMock;
20+
use Symfony\Bridge\PhpUnit\Metadata\AttributeReader;
1921

2022
/**
2123
* @internal
2224
*/
2325
class EnableClockMockSubscriber implements PreparationStartedSubscriber
2426
{
27+
public function __construct(
28+
private AttributeReader $reader,
29+
) {
30+
}
31+
2532
public function notify(PreparationStarted $event): void
2633
{
2734
$test = $event->test();
@@ -33,7 +40,12 @@ public function notify(PreparationStarted $event): void
3340
foreach ($test->metadata() as $metadata) {
3441
if ($metadata instanceof Group && 'time-sensitive' === $metadata->groupName()) {
3542
ClockMock::withClockMock(true);
43+
break;
3644
}
3745
}
46+
47+
if ($this->reader->forClassAndMethod($test->className(), $test->methodName(), TimeSensitive::class)) {
48+
ClockMock::withClockMock(true);
49+
}
3850
}
3951
}

src/Symfony/Bridge/PhpUnit/Extension/RegisterClockMockSubscriber.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@
1515
use PHPUnit\Event\TestSuite\Loaded;
1616
use PHPUnit\Event\TestSuite\LoadedSubscriber;
1717
use PHPUnit\Metadata\Group;
18+
use Symfony\Bridge\PhpUnit\Attribute\TimeSensitive;
1819
use Symfony\Bridge\PhpUnit\ClockMock;
20+
use Symfony\Bridge\PhpUnit\Metadata\AttributeReader;
1921

2022
/**
2123
* @internal
2224
*/
2325
class RegisterClockMockSubscriber implements LoadedSubscriber
2426
{
27+
public function __construct(
28+
private AttributeReader $reader,
29+
) {
30+
}
31+
2532
public function notify(Loaded $event): void
2633
{
2734
foreach ($event->testSuite()->tests() as $test) {
@@ -34,6 +41,10 @@ public function notify(Loaded $event): void
3441
ClockMock::register($test->className());
3542
}
3643
}
44+
45+
foreach ($this->reader->forClassAndMethod($test->className(), $test->methodName(), TimeSensitive::class) as $attribute) {
46+
ClockMock::register($attribute->class ?? $test->className());
47+
}
3748
}
3849
}
3950
}

src/Symfony/Bridge/PhpUnit/Extension/RegisterDnsMockSubscriber.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@
1515
use PHPUnit\Event\TestSuite\Loaded;
1616
use PHPUnit\Event\TestSuite\LoadedSubscriber;
1717
use PHPUnit\Metadata\Group;
18+
use Symfony\Bridge\PhpUnit\Attribute\DnsSensitive;
1819
use Symfony\Bridge\PhpUnit\DnsMock;
20+
use Symfony\Bridge\PhpUnit\Metadata\AttributeReader;
1921

2022
/**
2123
* @internal
2224
*/
2325
class RegisterDnsMockSubscriber implements LoadedSubscriber
2426
{
27+
public function __construct(
28+
private AttributeReader $reader,
29+
) {
30+
}
31+
2532
public function notify(Loaded $event): void
2633
{
2734
foreach ($event->testSuite()->tests() as $test) {
@@ -34,6 +41,10 @@ public function notify(Loaded $event): void
3441
DnsMock::register($test->className());
3542
}
3643
}
44+
45+
foreach ($this->reader->forClassAndMethod($test->className(), $test->methodName(), DnsSensitive::class) as $attribute) {
46+
DnsMock::register($attribute->class ?? $test->className());
47+
}
3748
}
3849
}
3950
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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\Metadata;
13+
14+
/**
15+
* @template T of object
16+
*/
17+
final class AttributeReader
18+
{
19+
/**
20+
* @var array<string, array<class-string<T>, list<T>>>
21+
*/
22+
private array $cache = [];
23+
24+
/**
25+
* @param class-string $className
26+
* @param class-string<T> $name
27+
*
28+
* @return list<T>
29+
*/
30+
public function forClass(string $className, string $name): array
31+
{
32+
$attributes = $this->cache[$className] ??= $this->readAttributes(new \ReflectionClass($className));
33+
34+
return $attributes[$name] ?? [];
35+
}
36+
37+
/**
38+
* @param class-string $className
39+
* @param class-string<T> $name
40+
*
41+
* @return list<T>
42+
*/
43+
public function forMethod(string $className, string $methodName, string $name): array
44+
{
45+
$attributes = $this->cache[$className.'::'.$methodName] ??= $this->readAttributes(new \ReflectionMethod($className, $methodName));
46+
47+
return $attributes[$name] ?? [];
48+
}
49+
50+
/**
51+
* @param class-string $className
52+
* @param class-string<T> $name
53+
*
54+
* @return list<T>
55+
*/
56+
public function forClassAndMethod(string $className, string $methodName, string $name): array
57+
{
58+
return [
59+
...$this->forClass($className, $name),
60+
...$this->forMethod($className, $methodName, $name),
61+
];
62+
}
63+
64+
private function readAttributes(\ReflectionClass|\ReflectionMethod $reflection): array
65+
{
66+
$attributeInstances = [];
67+
68+
foreach ($reflection->getAttributes() as $attribute) {
69+
if (!str_starts_with($name = $attribute->getName(), 'Symfony\\Bridge\\PhpUnit\\Attribute\\')) {
70+
continue;
71+
}
72+
73+
$attributeInstances[$name][] = $attribute->newInstance();
74+
}
75+
76+
return $attributeInstances;
77+
}
78+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy