-
Notifications
You must be signed in to change notification settings - Fork 1
/
Override.php
114 lines (99 loc) · 3.18 KB
/
Override.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<?php declare(strict_types = 1);
namespace LastDragon_ru\LaraASP\Testing\Concerns;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Testing\Concerns\InteractsWithContainer;
use LogicException;
use Mockery;
use Mockery\Exception\InvalidCountException;
use Mockery\MockInterface;
use OutOfBoundsException;
use Override as OverrideAttribute;
use PHPUnit\Framework\Attributes\Before;
use PHPUnit\Framework\TestCase;
use function assert;
use function is_callable;
use function is_string;
use function sprintf;
/**
* Similar to {@see InteractsWithContainer} but will mark test as failed if
* override was not used while test (that helps to find unused code).
*
* @see InteractsWithContainer
*
* @phpstan-require-extends TestCase
*/
trait Override {
/**
* @var array<class-string,MockInterface>
*/
private array $overrides = [];
abstract protected function app(): Application;
/**
* @internal
*/
#[Before]
protected function initOverride(): void {
$this->overrides = [];
}
#[OverrideAttribute]
protected function assertPostConditions(): void {
foreach ($this->overrides as $class => $spy) {
try {
$spy->shouldHaveBeenCalled();
} catch (InvalidCountException $exception) {
throw new OutOfBoundsException(
sprintf(
'Override for `%s` should be used at least 1 times but used 0 times.',
$class,
),
0,
$exception,
);
}
}
parent::assertPostConditions();
}
/**
* @template T
* @template TMock of T&MockInterface
*
* @param class-string<T> $class
* @param callable(TMock,static=):void|callable(TMock,static=):TMock|callable(TMock,static=):T|TMock|T|class-string<T>|null $factory
*
* @return TMock|T
*/
protected function override(string $class, mixed $factory = null): mixed {
// Overridden?
if (isset($this->overrides[$class])) {
throw new LogicException(
sprintf(
'Override for `%s` already defined.',
$class,
),
);
}
// Mock
/** @var TMock|T $mock */
$mock = is_callable($factory) || $factory === null
? Mockery::mock($class)
: $factory;
if (is_callable($factory)) {
$mock = $factory($mock, $this) ?? $mock;
} elseif (is_string($factory)) {
$mock = $this->app()->make($factory);
} else {
// empty
}
// Override
$this->overrides[$class] = Mockery::spy(static function () use ($mock): mixed {
return $mock;
});
assert(is_callable($this->overrides[$class]));
$this->app()->bind(
$class,
($this->overrides[$class])(...),
);
// Return
return $mock; // @phpstan-ignore-line return.type (`ContainerExtension` is not so smart yet).
}
}