Commit | Line | Data |
---|---|---|
ccc418af GS |
1 | #!./perl |
2 | ||
3 | BEGIN { | |
74517a3a | 4 | unshift @INC, 't'; |
9cd8f857 NC |
5 | require Config; |
6 | if (($Config::Config{'extensions'} !~ /\bB\b/) ){ | |
7 | print "1..0 # Skip -- Perl configured without B module\n"; | |
8 | exit 0; | |
9 | } | |
ccc418af GS |
10 | } |
11 | ||
12 | $| = 1; | |
13 | use warnings; | |
14 | use strict; | |
f9a20969 | 15 | use Test::More; |
ccc418af | 16 | |
c5f0f3aa | 17 | BEGIN { use_ok( 'B' ); } |
ccc418af | 18 | |
08c6f5ec | 19 | |
87a42246 MS |
20 | package Testing::Symtable; |
21 | use vars qw($This @That %wibble $moo %moo); | |
22 | my $not_a_sym = 'moo'; | |
ccc418af | 23 | |
87a42246 MS |
24 | sub moo { 42 } |
25 | sub car { 23 } | |
ccc418af | 26 | |
f70490b9 | 27 | |
87a42246 MS |
28 | package Testing::Symtable::Foo; |
29 | sub yarrow { "Hock" } | |
f70490b9 | 30 | |
87a42246 MS |
31 | package Testing::Symtable::Bar; |
32 | sub hock { "yarrow" } | |
9b86dfa2 | 33 | |
87a42246 MS |
34 | package main; |
35 | use vars qw(%Subs); | |
36 | local %Subs = (); | |
37 | B::walksymtable(\%Testing::Symtable::, 'find_syms', sub { $_[0] =~ /Foo/ }, | |
38 | 'Testing::Symtable::'); | |
ccc418af | 39 | |
87a42246 MS |
40 | sub B::GV::find_syms { |
41 | my($symbol) = @_; | |
de3f1649 | 42 | |
87a42246 | 43 | $main::Subs{$symbol->STASH->NAME . '::' . $symbol->NAME}++; |
cfe9256d | 44 | } |
ccc418af | 45 | |
87a42246 MS |
46 | my @syms = map { 'Testing::Symtable::'.$_ } qw(This That wibble moo car |
47 | BEGIN); | |
48 | push @syms, "Testing::Symtable::Foo::yarrow"; | |
ccc418af | 49 | |
87a42246 | 50 | # Make sure we hit all the expected symbols. |
c5f0f3aa | 51 | ok( join('', sort @syms) eq join('', sort keys %Subs), 'all symbols found' ); |
1e1dbab6 | 52 | |
87a42246 | 53 | # Make sure we only hit them each once. |
c5f0f3aa RGS |
54 | ok( (!grep $_ != 1, values %Subs), '...and found once' ); |
55 | ||
56 | # Tests for MAGIC / MOREMAGIC | |
57 | ok( B::svref_2object(\$.)->MAGIC->TYPE eq "\0", '$. has \0 magic' ); | |
58 | { | |
59 | my $e = ''; | |
60 | local $SIG{__DIE__} = sub { $e = $_[0] }; | |
61 | # Used to dump core, bug #16828 | |
62 | eval { B::svref_2object(\$.)->MAGIC->MOREMAGIC->TYPE; }; | |
63 | like( $e, qr/Can't call method "TYPE" on an undefined value/, | |
64 | '$. has no more magic' ); | |
65 | } | |
01b509b0 | 66 | |
de64752d NC |
67 | { |
68 | my $pie = 'Good'; | |
69 | # This needs to be a package variable, as vars in the pad have some flags. | |
70 | my $r = B::svref_2object(\$::data2); | |
71 | is($r->FLAGS(), 0, "uninitialised package variable has flags of 0"); | |
72 | is($r->SvTYPE(), 0, "uninitialised package variable has type 0"); | |
73 | is($r->POK(), 0, "POK false"); | |
74 | is($r->ROK(), 0, "ROK false"); | |
75 | is($r->MAGICAL(), 0, "MAGICAL false"); | |
76 | $::data2 = $pie; | |
77 | isnt($r->FLAGS(), 0, "initialised package variable has nonzero flags"); | |
78 | isnt($r->SvTYPE(), 0, "initialised package variable has nonzero type"); | |
79 | isnt($r->POK(), 0, "POK true"); | |
80 | is($r->ROK(), 0, "ROK false"); | |
81 | is($r->MAGICAL(), 0, "MAGICAL false"); | |
82 | ||
83 | $::data2 = substr $pie, 0, 1; | |
84 | isnt($r->FLAGS(), 0, "initialised package variable has nonzero flags"); | |
85 | isnt($r->SvTYPE(), 0, "initialised package variable has nonzero type"); | |
86 | isnt($r->POK(), 0, "POK true"); | |
87 | is($r->ROK(), 0, "ROK false"); | |
88 | is($r->MAGICAL(), 0, "MAGICAL true"); | |
89 | ||
90 | $::data2 = \$pie; | |
91 | isnt($r->FLAGS(), 0, "initialised package variable has nonzero flags"); | |
92 | isnt($r->SvTYPE(), 0, "initialised package variable has nonzero type"); | |
93 | is($r->POK(), 0, "POK false"); | |
94 | isnt($r->ROK(), 0, "ROK true"); | |
95 | is($r->MAGICAL(), 0, "MAGICAL false"); | |
96 | ||
97 | is($r->REFCNT(), 1, "Reference count is 1"); | |
98 | { | |
99 | my $ref = \$::data2; | |
100 | is($r->REFCNT(), 2, "Second reference"); | |
101 | } | |
102 | is($r->REFCNT(), 1, "Reference count is 1"); | |
103 | ||
104 | } | |
105 | ||
5c35adbb NC |
106 | my $r = qr/foo/; |
107 | my $obj = B::svref_2object($r); | |
108 | my $regexp = ($] < 5.011) ? $obj->MAGIC : $obj; | |
109 | ok($regexp->precomp() eq 'foo', 'Get string from qr//'); | |
110 | like($regexp->REGEX(), qr/\d+/, "REGEX() returns numeric value"); | |
01b509b0 SP |
111 | my $iv = 1; |
112 | my $iv_ref = B::svref_2object(\$iv); | |
113 | is(ref $iv_ref, "B::IV", "Test B:IV return from svref_2object"); | |
114 | is($iv_ref->REFCNT, 1, "Test B::IV->REFCNT"); | |
115 | # Flag tests are needed still | |
116 | #diag $iv_ref->FLAGS(); | |
117 | my $iv_ret = $iv_ref->object_2svref(); | |
118 | is(ref $iv_ret, "SCALAR", "Test object_2svref() return is SCALAR"); | |
119 | is($$iv_ret, $iv, "Test object_2svref()"); | |
120 | is($iv_ref->int_value, $iv, "Test int_value()"); | |
121 | is($iv_ref->IV, $iv, "Test IV()"); | |
122 | is($iv_ref->IVX(), $iv, "Test IVX()"); | |
123 | is($iv_ref->UVX(), $iv, "Test UVX()"); | |
f046b1bd NC |
124 | is(eval { $iv_ref->RV() }, undef, 'Test RV() on IV'); |
125 | like($@, qr/argument is not SvROK/, 'Test RV() IV'); | |
126 | $iv = \"Pie"; | |
127 | my $val = eval { $iv_ref->RV() }; | |
128 | is(ref $val, 'B::PV', 'Test RV() on a reference'); | |
129 | is($val->PV(), 'Pie', 'Value expected'); | |
130 | is($@, '', "Test RV()"); | |
01b509b0 SP |
131 | |
132 | my $pv = "Foo"; | |
133 | my $pv_ref = B::svref_2object(\$pv); | |
134 | is(ref $pv_ref, "B::PV", "Test B::PV return from svref_2object"); | |
135 | is($pv_ref->REFCNT, 1, "Test B::PV->REFCNT"); | |
136 | # Flag tests are needed still | |
137 | #diag $pv_ref->FLAGS(); | |
138 | my $pv_ret = $pv_ref->object_2svref(); | |
139 | is(ref $pv_ret, "SCALAR", "Test object_2svref() return is SCALAR"); | |
140 | is($$pv_ret, $pv, "Test object_2svref()"); | |
141 | is($pv_ref->PV(), $pv, "Test PV()"); | |
f046b1bd NC |
142 | is(eval { $pv_ref->RV() }, undef, 'Test RV() on PV'); |
143 | like($@, qr/argument is not SvROK/, 'Test RV() on PV'); | |
01b509b0 | 144 | is($pv_ref->PVX(), $pv, "Test PVX()"); |
f046b1bd NC |
145 | $pv = \"Pie"; |
146 | $val = eval { $pv_ref->RV() }; | |
147 | is(ref $val, 'B::PV', 'Test RV() on a reference'); | |
148 | is($val->PV(), 'Pie', 'Value expected'); | |
149 | is($@, '', "Test RV()"); | |
01b509b0 SP |
150 | |
151 | my $nv = 1.1; | |
152 | my $nv_ref = B::svref_2object(\$nv); | |
153 | is(ref $nv_ref, "B::NV", "Test B::NV return from svref_2object"); | |
154 | is($nv_ref->REFCNT, 1, "Test B::NV->REFCNT"); | |
155 | # Flag tests are needed still | |
156 | #diag $nv_ref->FLAGS(); | |
157 | my $nv_ret = $nv_ref->object_2svref(); | |
158 | is(ref $nv_ret, "SCALAR", "Test object_2svref() return is SCALAR"); | |
159 | is($$nv_ret, $nv, "Test object_2svref()"); | |
160 | is($nv_ref->NV, $nv, "Test NV()"); | |
161 | is($nv_ref->NVX(), $nv, "Test NVX()"); | |
f046b1bd NC |
162 | is(eval { $nv_ref->RV() }, undef, 'Test RV() on NV'); |
163 | like($@, qr/Can't locate object method "RV" via package "B::NV"/, | |
164 | 'Test RV() on NV'); | |
01b509b0 SP |
165 | |
166 | my $null = undef; | |
167 | my $null_ref = B::svref_2object(\$null); | |
168 | is(ref $null_ref, "B::NULL", "Test B::NULL return from svref_2object"); | |
169 | is($null_ref->REFCNT, 1, "Test B::NULL->REFCNT"); | |
170 | # Flag tests are needed still | |
171 | #diag $null_ref->FLAGS(); | |
172 | my $null_ret = $nv_ref->object_2svref(); | |
173 | is(ref $null_ret, "SCALAR", "Test object_2svref() return is SCALAR"); | |
174 | is($$null_ret, $nv, "Test object_2svref()"); | |
175 | ||
4df7f6af | 176 | my $RV_class = $] >= 5.011 ? 'B::IV' : 'B::RV'; |
01b509b0 SP |
177 | my $cv = sub{ 1; }; |
178 | my $cv_ref = B::svref_2object(\$cv); | |
4df7f6af NC |
179 | is($cv_ref->REFCNT, 1, "Test $RV_class->REFCNT"); |
180 | is(ref $cv_ref, "$RV_class", | |
181 | "Test $RV_class return from svref_2object - code"); | |
01b509b0 SP |
182 | my $cv_ret = $cv_ref->object_2svref(); |
183 | is(ref $cv_ret, "REF", "Test object_2svref() return is REF"); | |
184 | is($$cv_ret, $cv, "Test object_2svref()"); | |
185 | ||
186 | my $av = []; | |
187 | my $av_ref = B::svref_2object(\$av); | |
4df7f6af NC |
188 | is(ref $av_ref, "$RV_class", |
189 | "Test $RV_class return from svref_2object - array"); | |
01b509b0 SP |
190 | |
191 | my $hv = []; | |
192 | my $hv_ref = B::svref_2object(\$hv); | |
4df7f6af NC |
193 | is(ref $hv_ref, "$RV_class", |
194 | "Test $RV_class return from svref_2object - hash"); | |
01b509b0 SP |
195 | |
196 | local *gv = *STDOUT; | |
197 | my $gv_ref = B::svref_2object(\*gv); | |
198 | is(ref $gv_ref, "B::GV", "Test B::GV return from svref_2object"); | |
199 | ok(! $gv_ref->is_empty(), "Test is_empty()"); | |
711fbbf0 | 200 | ok($gv_ref->isGV_with_GP(), "Test isGV_with_GP()"); |
01b509b0 SP |
201 | is($gv_ref->NAME(), "gv", "Test NAME()"); |
202 | is($gv_ref->SAFENAME(), "gv", "Test SAFENAME()"); | |
203 | like($gv_ref->FILE(), qr/b\.t$/, "Testing FILE()"); | |
de64752d NC |
204 | is($gv_ref->SvTYPE(), B::SVt_PVGV, "Test SvTYPE()"); |
205 | is($gv_ref->FLAGS() & B::SVTYPEMASK, B::SVt_PVGV, "Test SVTYPEMASK"); | |
2da668d2 SP |
206 | |
207 | # The following return B::SPECIALs. | |
208 | is(ref B::sv_yes(), "B::SPECIAL", "B::sv_yes()"); | |
209 | is(ref B::sv_no(), "B::SPECIAL", "B::sv_no()"); | |
210 | is(ref B::sv_undef(), "B::SPECIAL", "B::sv_undef()"); | |
211 | ||
212 | # More utility functions | |
213 | is(B::ppname(0), "pp_null", "Testing ppname (this might break if opnames.h is changed)"); | |
214 | is(B::opnumber("null"), 0, "Testing opnumber with opname (null)"); | |
215 | is(B::opnumber("pp_null"), 0, "Testing opnumber with opname (pp_null)"); | |
b45732d6 NC |
216 | { |
217 | my $hash = B::hash("wibble"); | |
218 | like($hash, qr/\A0x[0-9a-f]+\z/, "Testing B::hash(\"wibble\")"); | |
219 | unlike($hash, qr/\A0x0+\z/, "Testing B::hash(\"wibble\")"); | |
220 | ||
bb1ca2d4 YO |
221 | SKIP: { |
222 | skip "Nulls don't hash to the same bucket regardless of length with this PERL_HASH implementation", 20 | |
223 | if B::hash("") ne B::hash("\0" x 19); | |
224 | like(B::hash("\0" x $_), qr/\A0x0+\z/, "Testing B::hash(\"0\" x $_)") | |
225 | for 0..19; | |
226 | } | |
8c5b7c71 NC |
227 | |
228 | $hash = eval {B::hash(chr 256)}; | |
229 | is($hash, undef, "B::hash() refuses non-octets"); | |
230 | like($@, qr/^Wide character in subroutine entry/); | |
231 | ||
232 | $hash = B::hash(chr 163); | |
233 | my $str = chr(163) . chr 256; | |
234 | chop $str; | |
235 | is(B::hash($str), $hash, 'B::hash() with chr 128-256 is well-behaved'); | |
b45732d6 | 236 | } |
f9a20969 NC |
237 | { |
238 | is(B::cstring(undef), '0', "Testing B::cstring(undef)"); | |
239 | is(B::perlstring(undef), '0', "Testing B::perlstring(undef)"); | |
240 | ||
241 | my @common = map {eval $_, $_} | |
574fde55 NC |
242 | '"wibble"', '"\""', '"\'"', '"\\\\"', '"\\n\\r\\t\\b\\a\\f"', '"\000"', |
243 | '"\000\000"', '"\000Bing\000"', ord 'N' == 78 ? '"\\177"' : (); | |
f9a20969 NC |
244 | |
245 | my $oct = sprintf "\\%03o", ord '?'; | |
246 | my @tests = (@common, '$_', '"$_"', '@_', '"@_"', '??N', qq{"$oct?N"}, | |
247 | ord 'N' == 78 ? (chr 11, '"\v"'): ()); | |
248 | while (my ($test, $expect) = splice @tests, 0, 2) { | |
249 | is(B::cstring($test), $expect, "B::cstring($expect)"); | |
250 | } | |
251 | ||
252 | @tests = (@common, '$_', '"\$_"', '@_', '"\@_"', '??N', '"??N"', | |
253 | chr 256, '"\x{100}"', chr 65536, '"\x{10000}"', | |
254 | ord 'N' == 78 ? (chr 11, '"\013"'): ()); | |
255 | while (my ($test, $expect) = splice @tests, 0, 2) { | |
256 | is(B::perlstring($test), $expect, "B::perlstring($expect)"); | |
257 | utf8::upgrade $test; | |
258 | $expect =~ s/\\b/\\x\{8\}/g; | |
259 | $expect =~ s/\\([0-7]{3})/sprintf "\\x\{%x\}", oct $1/eg; | |
260 | is(B::perlstring($test), $expect, "B::perlstring($expect) (Unicode)"); | |
261 | } | |
262 | } | |
01c3a485 | 263 | { |
574fde55 NC |
264 | my @tests = ((map {eval(qq{"$_"}), $_} '\\n', '\\r', '\\t', |
265 | '\\b', '\\a', '\\f', '\\000', '\\\'', '?'), '"', '"', | |
266 | ord 'N' == 78 ? (chr 11, '\v', "\177", '\\177') : ()); | |
01c3a485 NC |
267 | |
268 | while (my ($test, $expect) = splice @tests, 0, 2) { | |
269 | is(B::cchar($test), "'${expect}'", "B::cchar(qq{$expect})"); | |
270 | } | |
271 | } | |
272 | ||
2da668d2 SP |
273 | is(B::class(bless {}, "Wibble::Bibble"), "Bibble", "Testing B::class()"); |
274 | is(B::cast_I32(3.14), 3, "Testing B::cast_I32()"); | |
32b17be1 DM |
275 | is(B::opnumber("chop"), $] >= 5.015 ? 39 : 38, |
276 | "Testing opnumber with opname (chop)"); | |
5ce57cc0 JJ |
277 | |
278 | { | |
279 | no warnings 'once'; | |
280 | my $sg = B::sub_generation(); | |
e1a479c5 | 281 | *UNIVERSAL::hand_waving = sub { }; |
5ce57cc0 JJ |
282 | ok( $sg < B::sub_generation, "sub_generation increments" ); |
283 | } | |
284 | ||
3aaeec97 | 285 | like( B::amagic_generation, qr/^\d+\z/, "amagic_generation" ); |
f9a20969 | 286 | |
fdbd1d64 NC |
287 | is(B::svref_2object(sub {})->ROOT->ppaddr, 'PL_ppaddr[OP_LEAVESUB]', |
288 | 'OP->ppaddr'); | |
289 | ||
512ba29b FC |
290 | # This one crashes from perl 5.8.9 to B 1.24 (perl 5.13.6): |
291 | B::svref_2object(sub{y/\x{100}//})->ROOT->first->first->sibling->sv; | |
292 | ok 1, 'B knows that UTF trans is a padop in 5.8.9, not an svop'; | |
293 | ||
b852bf25 FR |
294 | { |
295 | format FOO = | |
296 | foo | |
297 | . | |
298 | my $f = B::svref_2object(*FOO{FORMAT}); | |
299 | isa_ok $f, 'B::FM'; | |
300 | can_ok $f, 'LINES'; | |
301 | } | |
302 | ||
a60c099b | 303 | my $sub1 = sub {die}; |
99225839 FC |
304 | { no warnings 'once'; no strict; *Peel:: = *{"Pe\0e\x{142}::"} } |
305 | my $sub2 = eval 'package Peel; sub {die}'; | |
a60c099b | 306 | my $cop = B::svref_2object($sub1)->ROOT->first->first; |
99225839 | 307 | my $bobby = B::svref_2object($sub2)->ROOT->first->first; |
a60c099b FC |
308 | is $cop->stash->object_2svref, \%main::, 'COP->stash'; |
309 | is $cop->stashpv, 'main', 'COP->stashpv'; | |
82aeefe1 DM |
310 | |
311 | SKIP: { | |
312 | skip "no nulls in packages before 5.17", 1 if $] < 5.017; | |
313 | is $bobby->stashpv, "Pe\0e\x{142}", 'COP->stashpv with utf8 and nulls'; | |
314 | } | |
315 | ||
316 | SKIP: { | |
317 | skip "no stashoff", 2 if $] < 5.017 || !$Config::Config{useithreads}; | |
99225839 FC |
318 | like $cop->stashoff, qr/^[1-9]\d*\z/a, 'COP->stashoff'; |
319 | isnt $cop->stashoff, $bobby->stashoff, | |
320 | 'different COP->stashoff for different stashes'; | |
a60c099b FC |
321 | } |
322 | ||
71324a3b DM |
323 | |
324 | # Test $B::overlay | |
325 | { | |
326 | my $methods = { | |
327 | BINOP => [ qw(last) ], | |
328 | COP => [ qw(arybase cop_seq file filegv hints hints_hash io | |
329 | label line stash stashpv | |
330 | stashoff warnings) ], | |
331 | LISTOP => [ qw(children) ], | |
332 | LOGOP => [ qw(other) ], | |
333 | LOOP => [ qw(lastop nextop redoop) ], | |
334 | OP => [ qw(desc flags name next opt ppaddr private sibling | |
335 | size spare targ type) ], | |
336 | PADOP => [ qw(gv padix sv) ], | |
337 | PMOP => [ qw(code_list pmflags pmoffset pmreplroot pmreplstart pmstash pmstashpv precomp reflags) ], | |
338 | PVOP => [ qw(pv) ], | |
339 | SVOP => [ qw(gv sv) ], | |
340 | UNOP => [ qw(first) ], | |
341 | }; | |
342 | ||
343 | my $overlay = {}; | |
344 | my $op = B::svref_2object(sub { my $x = 1 })->ROOT; | |
345 | ||
346 | for my $class (sort keys %$methods) { | |
347 | for my $meth (@{$methods->{$class}}) { | |
348 | my $full = "B::${class}::$meth"; | |
349 | die "Duplicate method '$full'\n" | |
350 | if grep $_ eq $full, @{$overlay->{$meth}}; | |
351 | push @{$overlay->{$meth}}, "B::${class}::$meth"; | |
352 | } | |
353 | } | |
354 | ||
355 | { | |
356 | local $B::overlay; # suppress 'used once' warning | |
357 | local $B::overlay = { $$op => $overlay }; | |
358 | ||
359 | for my $class (sort keys %$methods) { | |
360 | bless $op, "B::$class"; # naughty | |
361 | for my $meth (@{$methods->{$class}}) { | |
362 | if ($op->can($meth)) { | |
363 | my $list = $op->$meth; | |
364 | ok(defined $list | |
365 | && ref($list) eq "ARRAY" | |
366 | && grep($_ eq "B::${class}::$meth", @$list), | |
367 | "overlay: B::$class $meth"); | |
368 | } | |
369 | else { | |
370 | pass("overlay: B::$class $meth (skipped; no method)"); | |
371 | } | |
372 | } | |
373 | } | |
374 | } | |
375 | # B::overlay should be disabled again here | |
376 | is($op->name, "leavesub", "overlay: orig name"); | |
377 | } | |
378 | ||
486b1e7f TC |
379 | { # [perl #118525] |
380 | { | |
381 | sub foo {} | |
382 | my $cv = B::svref_2object(\&foo); | |
383 | ok($cv, "make a B::CV from a non-anon sub reference"); | |
384 | isa_ok($cv, "B::CV"); | |
385 | my $gv = $cv->GV; | |
386 | ok($gv, "we get a GV from a GV on a normal sub"); | |
387 | isa_ok($gv, "B::GV"); | |
388 | is($gv->NAME, "foo", "check the GV name"); | |
389 | SKIP: | |
390 | { # do we need these version checks? | |
391 | skip "no HEK before 5.18", 1 if $] < 5.018; | |
392 | is($cv->NAME_HEK, undef, "no hek for a global sub"); | |
393 | } | |
394 | } | |
395 | ||
396 | SKIP: | |
397 | { | |
398 | skip "no HEK before 5.18", 4 if $] < 5.018; | |
399 | eval <<'EOS' | |
400 | { | |
401 | use feature 'lexical_subs'; | |
402 | no warnings 'experimental::lexical_subs'; | |
403 | my sub bar {}; | |
404 | my $cv = B::svref_2object(\&bar); | |
405 | ok($cv, "make a B::CV from a lexical sub reference"); | |
406 | isa_ok($cv, "B::CV"); | |
407 | my $gv = $cv->GV; | |
31d07368 | 408 | isa_ok($gv, "B::SPECIAL", "GV on a lexical sub"); |
486b1e7f TC |
409 | my $hek = $cv->NAME_HEK; |
410 | is($hek, "bar", "check the NAME_HEK"); | |
411 | } | |
412 | 1; | |
413 | EOS | |
414 | or die "lexical_subs test failed to compile: $@"; | |
415 | } | |
416 | } | |
417 | ||
cc54be84 | 418 | { # [perl #120535] |
cc54be84 TC |
419 | my %h = ( "\x{100}" => 1 ); |
420 | my $b = B::svref_2object(\%h); | |
421 | my ($k, $v) = $b->ARRAY; | |
422 | is($k, "\x{100}", "check utf8 preserved by B::HV::ARRAY"); | |
423 | } | |
424 | ||
f9a20969 | 425 | done_testing(); |