This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade Test-Simple from version 1.302122 to 1.302133
[perl5.git] / cpan / Test-Simple / t / Test2 / modules / Hub.t
1 use strict;
2 use warnings;
3
4 use Test2::IPC;
5 use Test2::Tools::Tiny;
6 use Test2::API qw/context test2_ipc_drivers/;
7 use Test2::Util qw/CAN_FORK CAN_THREAD CAN_REALLY_FORK/;
8
9 {
10     package My::Formatter;
11
12     sub new { bless [], shift };
13
14     my $check = 1;
15     sub write {
16         my $self = shift;
17         my ($e, $count) = @_;
18         push @$self => $e;
19     }
20 }
21
22 {
23     package My::Event;
24
25     use base 'Test2::Event';
26     use Test2::Util::HashBase qw{msg};
27 }
28
29 tests basic => sub {
30     my $hub = Test2::Hub->new(
31         formatter => My::Formatter->new,
32     );
33
34     my $send_event = sub {
35         my ($msg) = @_;
36         my $e = My::Event->new(msg => $msg, trace => Test2::EventFacet::Trace->new(frame => ['fake', 'fake.t', 1]));
37         $hub->send($e);
38     };
39
40     ok(my $e1 = $send_event->('foo'), "Created event");
41     ok(my $e2 = $send_event->('bar'), "Created event");
42     ok(my $e3 = $send_event->('baz'), "Created event");
43
44     my $old = $hub->format(My::Formatter->new);
45
46     ok($old->isa('My::Formatter'), "old formatter");
47     is_deeply(
48         $old,
49         [$e1, $e2, $e3],
50         "Formatter got all events"
51     );
52 };
53
54 tests follow_ups => sub {
55     my $hub = Test2::Hub->new;
56     $hub->set_count(1);
57
58     my $trace = Test2::EventFacet::Trace->new(
59         frame => [__PACKAGE__, __FILE__, __LINE__],
60     );
61
62     my $ran = 0;
63     $hub->follow_up(sub {
64         my ($d, $h) = @_;
65         is_deeply($d, $trace, "Got trace");
66         is_deeply($h, $hub, "Got hub");
67         ok(!$hub->ended, "Hub state has not ended yet");
68         $ran++;
69     });
70
71     like(
72         exception { $hub->follow_up('xxx') },
73         qr/follow_up only takes coderefs for arguments, got 'xxx'/,
74         "follow_up takes a coderef"
75     );
76
77     $hub->finalize($trace);
78
79     is($ran, 1, "ran once");
80
81     is_deeply(
82         $hub->ended,
83         $trace->frame,
84         "Ended at the expected place."
85     );
86
87     eval { $hub->finalize($trace) };
88
89     is($ran, 1, "ran once");
90
91     $hub = undef;
92 };
93
94 tests IPC => sub {
95     my ($driver) = test2_ipc_drivers();
96     is($driver, 'Test2::IPC::Driver::Files', "Default Driver");
97     my $ipc = $driver->new;
98     my $hub = Test2::Hub->new(
99         formatter => My::Formatter->new,
100         ipc => $ipc,
101     );
102
103     my $build_event = sub {
104         my ($msg) = @_;
105         return My::Event->new(msg => $msg, trace => Test2::EventFacet::Trace->new(frame => ['fake', 'fake.t', 1]));
106     };
107
108     my $e1 = $build_event->('foo');
109     my $e2 = $build_event->('bar');
110     my $e3 = $build_event->('baz');
111
112     my $do_send = sub {
113         $hub->send($e1);
114         $hub->send($e2);
115         $hub->send($e3);
116     };
117
118     my $do_check = sub {
119         my $name = shift;
120
121         my $old = $hub->format(My::Formatter->new);
122
123         ok($old->isa('My::Formatter'), "old formatter");
124         is(@$old, 3, "Formatter got all events ($name)");
125         ok($_->{hubs}, "Set the hubs") for @$old;
126     };
127
128     if (CAN_REALLY_FORK) {
129         my $pid = fork();
130         die "Could not fork!" unless defined $pid;
131
132         if ($pid) {
133             is(waitpid($pid, 0), $pid, "waited properly");
134             ok(!$?, "child exited with success");
135             $hub->cull();
136             $do_check->('Fork');
137         }
138         else {
139             $do_send->();
140             exit 0;
141         }
142     }
143
144     if (CAN_THREAD && $] ge '5.010') {
145         require threads;
146         my $thr = threads->new(sub { $do_send->() });
147         $thr->join;
148         $hub->cull();
149         $do_check->('Threads');
150     }
151
152     $do_send->();
153     $hub->cull();
154     $do_check->('no IPC');
155 };
156
157 tests listen => sub {
158     my $hub = Test2::Hub->new();
159
160     my @events;
161     my @counts;
162     my $it = $hub->listen(sub {
163         my ($h, $e, $count) = @_;
164         is_deeply($h, $hub, "got hub");
165         push @events => $e;
166         push @counts => $count;
167     });
168
169     my $second;
170     my $it2 = $hub->listen(sub { $second++ });
171
172     my $ok1 = Test2::Event::Ok->new(
173         pass => 1,
174         name => 'foo',
175         trace => Test2::EventFacet::Trace->new(
176             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
177         ),
178     );
179
180     my $ok2 = Test2::Event::Ok->new(
181         pass => 0,
182         name => 'bar',
183         trace => Test2::EventFacet::Trace->new(
184             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
185         ),
186     );
187
188     my $ok3 = Test2::Event::Ok->new(
189         pass => 1,
190         name => 'baz',
191         trace => Test2::EventFacet::Trace->new(
192             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
193         ),
194     );
195
196     $hub->send($ok1);
197     $hub->send($ok2);
198
199     $hub->unlisten($it);
200
201     $hub->send($ok3);
202
203     is_deeply(\@counts, [1, 2], "Got counts");
204     is_deeply(\@events, [$ok1, $ok2], "got events");
205     is($second, 3, "got all events in listener that was not removed");
206
207     like(
208         exception { $hub->listen('xxx') },
209         qr/listen only takes coderefs for arguments, got 'xxx'/,
210         "listen takes a coderef"
211     );
212 };
213
214 tests metadata => sub {
215     my $hub = Test2::Hub->new();
216
217     my $default = { foo => 1 };
218     my $meta = $hub->meta('Foo', $default);
219     is_deeply($meta, $default, "Set Meta");
220
221     $meta = $hub->meta('Foo', {});
222     is_deeply($meta, $default, "Same Meta");
223
224     $hub->delete_meta('Foo');
225     is($hub->meta('Foo'), undef, "No Meta");
226
227     $hub->meta('Foo', {})->{xxx} = 1;
228     is($hub->meta('Foo')->{xxx}, 1, "Vivified meta and set it");
229
230     like(
231         exception { $hub->meta(undef) },
232         qr/Invalid META key: undef, keys must be true, and may not be references/,
233         "Cannot use undef as a meta key"
234     );
235
236     like(
237         exception { $hub->meta(0) },
238         qr/Invalid META key: '0', keys must be true, and may not be references/,
239         "Cannot use 0 as a meta key"
240     );
241
242     like(
243         exception { $hub->delete_meta(undef) },
244         qr/Invalid META key: undef, keys must be true, and may not be references/,
245         "Cannot use undef as a meta key"
246     );
247
248     like(
249         exception { $hub->delete_meta(0) },
250         qr/Invalid META key: '0', keys must be true, and may not be references/,
251         "Cannot use 0 as a meta key"
252     );
253 };
254
255 tests filter => sub {
256     my $hub = Test2::Hub->new();
257
258     my @events;
259     my $it = $hub->filter(sub {
260         my ($h, $e) = @_;
261         is($h, $hub, "got hub");
262         push @events => $e;
263         return $e;
264     });
265
266     my $count;
267     my $it2 = $hub->filter(sub { $count++; $_[1] });
268
269     my $ok1 = Test2::Event::Ok->new(
270         pass => 1,
271         name => 'foo',
272         trace => Test2::EventFacet::Trace->new(
273             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
274         ),
275     );
276
277     my $ok2 = Test2::Event::Ok->new(
278         pass => 0,
279         name => 'bar',
280         trace => Test2::EventFacet::Trace->new(
281             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
282         ),
283     );
284
285     my $ok3 = Test2::Event::Ok->new(
286         pass => 1,
287         name => 'baz',
288         trace => Test2::EventFacet::Trace->new(
289             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
290         ),
291     );
292
293     $hub->send($ok1);
294     $hub->send($ok2);
295
296     $hub->unfilter($it);
297
298     $hub->send($ok3);
299
300     is_deeply(\@events, [$ok1, $ok2], "got events");
301     is($count, 3, "got all events, even after other filter was removed");
302
303     $hub = Test2::Hub->new();
304     @events = ();
305
306     $hub->filter(sub { undef });
307     $hub->listen(sub {
308         my ($hub, $e) = @_;
309         push @events => $e;
310     });
311
312     $hub->send($ok1);
313     $hub->send($ok2);
314     $hub->send($ok3);
315
316     ok(!@events, "Blocked events");
317
318     like(
319         exception { $hub->filter('xxx') },
320         qr/filter only takes coderefs for arguments, got 'xxx'/,
321         "filter takes a coderef"
322     );
323 };
324
325 tests pre_filter => sub {
326     my $hub = Test2::Hub->new();
327
328     my @events;
329     my $it = $hub->pre_filter(sub {
330         my ($h, $e) = @_;
331         is($h, $hub, "got hub");
332         push @events => $e;
333         return $e;
334     });
335
336     my $count;
337     my $it2 = $hub->pre_filter(sub { $count++; $_[1] });
338
339     my $ok1 = Test2::Event::Ok->new(
340         pass => 1,
341         name => 'foo',
342         trace => Test2::EventFacet::Trace->new(
343             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
344         ),
345     );
346
347     my $ok2 = Test2::Event::Ok->new(
348         pass => 0,
349         name => 'bar',
350         trace => Test2::EventFacet::Trace->new(
351             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
352         ),
353     );
354
355     my $ok3 = Test2::Event::Ok->new(
356         pass => 1,
357         name => 'baz',
358         trace => Test2::EventFacet::Trace->new(
359             frame => [ __PACKAGE__, __FILE__, __LINE__ ],
360         ),
361     );
362
363     $hub->send($ok1);
364     $hub->send($ok2);
365
366     $hub->pre_unfilter($it);
367
368     $hub->send($ok3);
369
370     is_deeply(\@events, [$ok1, $ok2], "got events");
371     is($count, 3, "got all events, even after other pre_filter was removed");
372
373     $hub = Test2::Hub->new();
374     @events = ();
375
376     $hub->pre_filter(sub { undef });
377     $hub->listen(sub {
378         my ($hub, $e) = @_;
379         push @events => $e;
380     });
381
382     $hub->send($ok1);
383     $hub->send($ok2);
384     $hub->send($ok3);
385
386     ok(!@events, "Blocked events");
387
388     like(
389         exception { $hub->pre_filter('xxx') },
390         qr/pre_filter only takes coderefs for arguments, got 'xxx'/,
391         "pre_filter takes a coderef"
392     );
393 };
394
395 tests state => sub {
396     my $hub = Test2::Hub->new;
397
398     is($hub->count,      0,     "count starts at 0");
399     is($hub->failed,     0,     "failed starts at 0");
400     is($hub->is_passing, 1,     "start off passing");
401     is($hub->plan,       undef, "no plan yet");
402
403     $hub->is_passing(0);
404     is($hub->is_passing, 0, "Can Fail");
405
406     $hub->is_passing(1);
407     is($hub->is_passing, 1, "Passes again");
408
409     $hub->set_count(1);
410     is($hub->count,      1, "Added a passing result");
411     is($hub->failed,     0, "still no fails");
412     is($hub->is_passing, 1, "Still passing");
413
414     $hub->set_count(2);
415     $hub->set_failed(1);
416     is($hub->count,      2, "Added a result");
417     is($hub->failed,     1, "new failure");
418     is($hub->is_passing, 0, "Not passing");
419
420     $hub->is_passing(1);
421     is($hub->is_passing, 0, "is_passing always false after a failure");
422
423     $hub->set_failed(0);
424     $hub->is_passing(1);
425     is($hub->is_passing, 1, "Passes again");
426
427     $hub->set_failed(1);
428     is($hub->count,      2, "No new result");
429     is($hub->failed,     1, "new failure");
430     is($hub->is_passing, 0, "Not passing");
431
432     ok(!eval { $hub->plan('foo'); 1 }, "Could not set plan to 'foo'");
433     like($@, qr/'foo' is not a valid plan! Plan must be an integer greater than 0, 'NO PLAN', or 'SKIP'/, "Got expected error");
434
435     ok($hub->plan(5), "Can set plan to integer");
436     is($hub->plan, 5, "Set the plan to an integer");
437
438     $hub->set__plan(undef);
439     ok($hub->plan('NO PLAN'), "Can set plan to 'NO PLAN'");
440     is($hub->plan, 'NO PLAN', "Set the plan to 'NO PLAN'");
441
442     $hub->set__plan(undef);
443     ok($hub->plan('SKIP'), "Can set plan to 'SKIP'");
444     is($hub->plan, 'SKIP', "Set the plan to 'SKIP'");
445
446     ok(!eval { $hub->plan(5); 1 }, "Cannot change plan");
447     like($@, qr/You cannot change the plan/, "Got error");
448
449     my $trace = Test2::EventFacet::Trace->new(frame => ['Foo::Bar', 'foo.t', 42, 'blah']);
450     $hub->finalize($trace);
451     my $ok = eval { $hub->finalize($trace) };
452     my $err = $@;
453     ok(!$ok, "died");
454
455     is($err, <<"    EOT", "Got expected error");
456 Test already ended!
457 First End:  foo.t line 42
458 Second End: foo.t line 42
459     EOT
460
461     $hub = Test2::Hub->new;
462
463     $hub->plan(5);
464     $hub->set_count(5);
465     $hub->set_failed(1);
466     $hub->set_ended($trace);
467     $hub->set_bailed_out("foo");
468     $hub->set_skip_reason('xxx');
469     ok(!$hub->is_passing, "not passing");
470
471     $hub->reset_state;
472
473     ok(!$hub->plan, "no plan");
474     is($hub->count, 0, "count reset to 0");
475     is($hub->failed, 0, "reset failures");
476     ok(!$hub->ended, "not ended");
477     ok(!$hub->bailed_out, "did not bail out");
478     ok(!$hub->skip_reason, "no skip reason");
479 };
480
481 done_testing;