-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEventTest.php
142 lines (115 loc) · 4.43 KB
/
EventTest.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<?php
namespace Test\ICanBoogie;
use Error;
use ICanBoogie\EventCollection;
use ICanBoogie\EventCollectionProvider;
use PHPUnit\Framework\TestCase;
use Test\ICanBoogie\Sample\Processor;
use Test\ICanBoogie\Sample\Processor\BeforeProcessEvent;
use Test\ICanBoogie\Sample\Processor\ProcessEvent;
use Test\ICanBoogie\Sample\Processor\ValidateEvent;
use Test\ICanBoogie\Sample\ProcessorExtension;
use Test\ICanBoogie\Sample\SampleEvent;
use Test\ICanBoogie\Sample\SampleSender;
use function ICanBoogie\emit;
final class EventTest extends TestCase
{
private EventCollection $events;
protected function setUp(): void
{
$this->events = new EventCollection();
EventCollectionProvider::define(fn() => $this->events);
}
public function test_uninitialized_sender(): void
{
$event = new SampleEvent();
$this->expectException(Error::class);
$this->expectExceptionMessageMatches("/sender must not be accessed before initialization/");
$this->assertNull($event->sender); // @phpstan-ignore-line
}
public function test_for(): void
{
$this->assertEquals(
"Test\ICanBoogie\Sample\SampleSender::Test\ICanBoogie\Sample\Processor\BeforeProcessEvent",
BeforeProcessEvent::for(SampleSender::class)
);
}
public function test_stop(): void
{
$n = 0;
$this->events->attach(SampleEvent::class, function (SampleEvent $event) use (&$n) {
$n++;
});
$this->events->attach(SampleEvent::class, function (SampleEvent $event) {
$event->stop();
});
$event = emit(new SampleEvent());
$this->assertTrue($event->stopped);
$this->assertEquals(0, $n);
}
public function test_sender(): void
{
$sender = new SampleSender();
$event = new SampleEvent($sender);
$this->assertSame($sender, $event->sender);
}
/**
* The big test, with reflection and chains.
*/
public function testEventHooks(): void
{
/*
* The A::validate() method would return false if the following hook wasn't called.
*/
$this->events->attach(function (ValidateEvent $event, Processor $sender) {
$event->valid = true;
});
/*
* We add "three" to the values before they're processed.
*/
$this->events->attach(function (BeforeProcessEvent $event, Processor $sender) {
$event->values['three'] = 3;
});
/*
* This hook is called before any hook set on the A class, because we want "four" to be
* after "three", which is added by the hook above, we use the _chain_ feature of the event.
*
* Hooks pushed by the chain() method are executed after the even chain was processed.
*/
$this->events->attach(function (BeforeProcessEvent $event, ProcessorExtension $sender) {
$event->chain(function ($event) {
$event->values['four'] = 4;
});
});
/*
* 10 is added to all processed values of A instances.
*/
$this->events->attach(function (ProcessEvent $event, Processor $sender) {
array_walk($event->values, function (&$v) {
$v += 10;
});
});
/*
* We want processed values to be mutiplied by 10 for B instances, because 10 is already added to
* values of A instances we need to stop the event from propagating.
*
* The stop() method of the event breaks the event chain, so our hook will be the last
* called in the chain.
*/
$this->events->attach(function (ProcessEvent $event, ProcessorExtension $sender) {
array_walk($event->values, function (&$v) {
$v *= 10;
});
$event->stop();
});
$initial_array = [ 'one' => 1, 'two' => 2 ];
$a = new Processor();
$b = new ProcessorExtension();
$a_processed = $a($initial_array);
$b_processed = $b($initial_array);
$this->assertEquals([ 'one' => 11, 'two' => 12, 'three' => 13 ], $a_processed);
$this->assertEquals('one,two,three', implode(',', array_keys($a_processed)));
$this->assertEquals([ 'one' => 10, 'two' => 20, 'three' => 30, 'four' => 40, 'five' => 50 ], $b_processed);
$this->assertEquals('one,two,three,four,five', implode(',', array_keys($b_processed)));
}
}