File: 04notifier.t

package info (click to toggle)
libio-async-perl 0.64-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,068 kB
  • ctags: 491
  • sloc: perl: 12,530; makefile: 8
file content (194 lines) | stat: -rw-r--r-- 5,679 bytes parent folder | download | duplicates (5)
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#!/usr/bin/perl

use strict;
use warnings;

use Test::More;
use Test::Fatal;
use Test::Refcount;

use IO::Async::Notifier;

{
   my $notifier = IO::Async::Notifier->new(
      notifier_name => "test1",
   );

   ok( defined $notifier, '$notifier defined' );
   isa_ok( $notifier, "IO::Async::Notifier", '$notifier isa IO::Async::Notifier' );

   is_oneref( $notifier, '$notifier has refcount 1 initially' );

   is( $notifier->notifier_name, "test1", '$notifier->notifier_name' );

   ok( !exception { $notifier->configure; },
      '$notifier->configure no params succeeds' );

   ok( exception { $notifier->configure( oranges => 1 ) },
      '$notifier->configure an unknown parameter fails' );

   my %other;
   no warnings 'redefine';
   local *IO::Async::Notifier::configure_unknown = sub {
      shift;
      %other = @_;
   };

   ok( !exception { $notifier->configure( oranges => 3 ) },
       '$notifier->configure with configure_unknown succeeds' );

   is_deeply( \%other, { oranges => 3 }, '%other after configure_unknown' );
}

# weaseling
{
   my $notifier = IO::Async::Notifier->new;

   my @args;
   my $mref = $notifier->_capture_weakself( sub { @args = @_ } );

   is_oneref( $notifier, '$notifier has refcount 1 after _capture_weakself' );

   $mref->( 123 );
   is_deeply( \@args, [ $notifier, 123 ], '@args after invoking $mref' );

   my @callstack;
   $notifier->_capture_weakself( sub {
      my $level = 0;
      push @callstack, [ (caller $level++)[0,3] ] while defined caller $level;
   } )->();

   is_deeply( \@callstack,
              [ [ "main", "main::__ANON__" ] ],
              'trampoline does not appear in _capture_weakself callstack' );

   undef @args;

   $mref = $notifier->_replace_weakself( sub { @args = @_ } );

   is_oneref( $notifier, '$notifier has refcount 1 after _replace_weakself' );

   my $outerself = bless [], "OtherClass";
   $mref->( $outerself, 456 );
   is_deeply( \@args, [ $notifier, 456 ], '@args after invoking replacer $mref' );

   isa_ok( $outerself, "OtherClass", '$outerself unchanged' );

   ok( exception { $notifier->_capture_weakself( 'cannotdo' ) },
       '$notifier->_capture_weakself on unknown method name fails' );
}

# Subclass
{
   my @subargs;
   {
      package TestNotifier;
      use base qw( IO::Async::Notifier );

      sub frobnicate { @subargs = @_ }
   }

   my $subn = TestNotifier->new;

   my $mref = $subn->_capture_weakself( 'frobnicate' );

   is_oneref( $subn, '$subn has refcount 1 after _capture_weakself on named method' );

   $mref->( 456 );
   is_deeply( \@subargs, [ $subn, 456 ], '@subargs after invoking $mref on named method' );

   undef @subargs;

   # Method capture
   {
      my @newargs;

      no warnings 'redefine';
      local *TestNotifier::frobnicate = sub { @newargs = @_; };

      $mref->( 321 );

      is_deeply( \@subargs, [], '@subargs empty after TestNotifier::frobnicate replacement' );
      is_deeply( \@newargs, [ $subn, 321 ], '@newargs after TestNotifier::frobnicate replacement' );
   }

   undef @subargs;

   $subn->invoke_event( 'frobnicate', 78 );
   is_deeply( \@subargs, [ $subn, 78 ], '@subargs after ->invoke_event' );

   undef @subargs;

   is_deeply( $subn->maybe_invoke_event( 'frobnicate', 'a'..'c' ),
              [ $subn, 'a'..'c' ],
              'return value from ->maybe_invoke_event' );

   is( $subn->maybe_invoke_event( 'mangle' ), undef, 'return value from ->maybe_invoke_event on missing event' );

   undef @subargs;

   my $cb = $subn->make_event_cb( 'frobnicate' );

   is( ref $cb, "CODE", '->make_event_cb returns a CODE reference' );
   is_oneref( $subn, '$subn has refcount 1 after ->make_event_cb' );

   $cb->( 90 );
   is_deeply( \@subargs, [ $subn, 90 ], '@subargs after ->make_event_cb->()' );

   isa_ok( $subn->maybe_make_event_cb( 'frobnicate' ), "CODE", '->maybe_make_event_cb yields CODE ref' );
   is( $subn->maybe_make_event_cb( 'mangle' ), undef, '->maybe_make_event_cb on missing event yields undef' );

   undef @subargs;

   is_oneref( $subn, '$subn has refcount 1 finally' );
}

# parent/child
{
   my $parent = IO::Async::Notifier->new;
   my $child = IO::Async::Notifier->new;

   is_oneref( $parent, '$parent has refcount 1 initially' );
   is_oneref( $child, '$child has refcount 1 initially' );

   $parent->add_child( $child );

   is( $child->parent, $parent, '$child->parent is $parent' );
   is_deeply( [ $parent->children ], [ $child ], '$parent->children' );

   is_oneref( $parent, '$parent has refcount 1 after add_child' );
   is_refcount( $child, 2, '$child has refcount 2 after add_child' );

   ok( exception { $parent->add_child( $child ) }, 'Adding child again fails' );

   $parent->remove_child( $child );

   is_oneref( $child, '$child has refcount 1 after remove_child' );
   is_deeply( [ $parent->children ], [], '$parent->children now empty' );
}

# invoke_error
{
   my $parent = IO::Async::Notifier->new;
   my $child = IO::Async::Notifier->new;

   $parent->add_child( $child );

   # invoke_error no handler
   ok( exception { $parent->invoke_error( "It went wrong", wrong => ) },
       'Exception thrown from ->invoke_error with no handler' );

   # invoke_error handler
   my $err;
   $parent->configure( on_error => sub { $err = $_[1] } );

   ok( !exception { $parent->invoke_error( "It's still wrong", wrong => ) },
       'Exception not thrown from ->invoke_error with handler' );
   is( $err, "It's still wrong", '$message to on_error' );

   ok( !exception { $child->invoke_error( "Wrong on child", wrong => ) },
       'Exception not thrown from ->invoke_error on child' );
   is( $err, "Wrong on child", '$message to parent on_error' );
}

done_testing;