xref: /openbsd-src/gnu/usr.bin/perl/t/op/numify_chkflags.t (revision 256a93a44f36679bee503f12e49566c2183f6181)
1*256a93a4Safresh1#! ./perl
2*256a93a4Safresh1
3*256a93a4Safresh1# Check conversions of PV to NV/IV/UV
4*256a93a4Safresh1
5*256a93a4Safresh1BEGIN {
6*256a93a4Safresh1    chdir 't' if -d 't';
7*256a93a4Safresh1    require './test.pl';
8*256a93a4Safresh1    set_up_inc('../lib');
9*256a93a4Safresh1    skip_all_without_dynamic_extension('Devel::Peek');
10*256a93a4Safresh1}
11*256a93a4Safresh1
12*256a93a4Safresh1use strict;
13*256a93a4Safresh1use warnings;
14*256a93a4Safresh1use Devel::Peek;
15*256a93a4Safresh1use Config;
16*256a93a4Safresh1
17*256a93a4Safresh1# Use Devel::Peek::Dump in order to investigate SV flags for checking
18*256a93a4Safresh1# conversion behavior precisely.
19*256a93a4Safresh1# But unfortunately Devel::Peek::Dump always outputs to stderr, so
20*256a93a4Safresh1# a small wrapper to capture stderr into Perl string is implemented here
21*256a93a4Safresh1# to automate the test.
22*256a93a4Safresh1
23*256a93a4Safresh1package STDERRSaver {
24*256a93a4Safresh1    sub new {
25*256a93a4Safresh1        open my $old, '>&', *STDERR or die "Can't save STDERR: $!";
26*256a93a4Safresh1        close STDERR;
27*256a93a4Safresh1        open STDERR, $_[1], $_[2] or die "Can't redirect STDERR: $!";
28*256a93a4Safresh1        bless \$old, $_[0] || __PACKAGE__;
29*256a93a4Safresh1    }
30*256a93a4Safresh1    sub DESTROY {
31*256a93a4Safresh1        open STDERR, '>&', ${$_[0]} or die "Can't restore STDERR: $!";
32*256a93a4Safresh1        close ${$_[0]};
33*256a93a4Safresh1    }
34*256a93a4Safresh1}
35*256a93a4Safresh1
36*256a93a4Safresh1# These functions use &sub form to minimize argument manipulation.
37*256a93a4Safresh1
38*256a93a4Safresh1sub capture_dump
39*256a93a4Safresh1{
40*256a93a4Safresh1    my $str;
41*256a93a4Safresh1    my @warnings;
42*256a93a4Safresh1    eval {
43*256a93a4Safresh1        local $SIG{__WARN__} = sub { push @warnings, $_[0] };
44*256a93a4Safresh1        my $err = STDERRSaver->new('>', \$str);
45*256a93a4Safresh1        &Dump;
46*256a93a4Safresh1        !0;
47*256a93a4Safresh1    } or BAIL_OUT $@;           # Avoid die() under test.
48*256a93a4Safresh1    note(@warnings) if @warnings;
49*256a93a4Safresh1    $str;
50*256a93a4Safresh1}
51*256a93a4Safresh1
52*256a93a4Safresh1# Implement Sv*OK in Perl.
53*256a93a4Safresh1
54*256a93a4Safresh1sub sv_flags
55*256a93a4Safresh1{
56*256a93a4Safresh1    my $dump = &capture_dump;
57*256a93a4Safresh1    $dump =~ /^\h*FLAGS\h*=\h*\(\h*(.*?)\h*\)/m # be tolerant
58*256a93a4Safresh1        or note($dump), BAIL_OUT 'Cannot parse Devel::Peek::Dump output';
59*256a93a4Safresh1    +{ map { $_ => !0 } split /\h*,\h*/, $1 };
60*256a93a4Safresh1}
61*256a93a4Safresh1
62*256a93a4Safresh1sub SvUOK
63*256a93a4Safresh1{
64*256a93a4Safresh1    my $flags = &sv_flags;
65*256a93a4Safresh1    $flags->{IOK} && $flags->{IsUV};
66*256a93a4Safresh1}
67*256a93a4Safresh1
68*256a93a4Safresh1sub SvUOKp
69*256a93a4Safresh1{
70*256a93a4Safresh1    my $flags = &sv_flags;
71*256a93a4Safresh1    $flags->{pIOK} && $flags->{IsUV};
72*256a93a4Safresh1}
73*256a93a4Safresh1
74*256a93a4Safresh1sub SvIOKp_notIOK_notUV
75*256a93a4Safresh1{
76*256a93a4Safresh1    my $flags = &sv_flags;
77*256a93a4Safresh1    $flags->{pIOK} && !$flags->{IOK} && !$flags->{IsUV};
78*256a93a4Safresh1}
79*256a93a4Safresh1
80*256a93a4Safresh1sub SvIOK_notUV
81*256a93a4Safresh1{
82*256a93a4Safresh1    my $flags = &sv_flags;
83*256a93a4Safresh1    $flags->{IOK} && !$flags->{IsUV};
84*256a93a4Safresh1}
85*256a93a4Safresh1
86*256a93a4Safresh1sub SvNOK
87*256a93a4Safresh1{
88*256a93a4Safresh1    (&sv_flags)->{NOK};
89*256a93a4Safresh1}
90*256a93a4Safresh1
91*256a93a4Safresh1# This will be a quick test of Sv*OK* implemented here.
92*256a93a4Safresh1ok(SvIOK_notUV(2147483647), '2147483647 is not UV');
93*256a93a4Safresh1
94*256a93a4Safresh1{
95*256a93a4Safresh1    my $x = '12345.67';
96*256a93a4Safresh1    my $y = $x;
97*256a93a4Safresh1    my $z = $y << 0;            # "<<" requires UV operands
98*256a93a4Safresh1    is($z, 12345, "string '$x' to UV conversion");
99*256a93a4Safresh1    ok(SvIOKp_notIOK_notUV($y), 'string to UV conversion caches IV');
100*256a93a4Safresh1    is($y >> 0, 12345, 'reusing cached IV');
101*256a93a4Safresh1}
102*256a93a4Safresh1
103*256a93a4Safresh1{
104*256a93a4Safresh1    my $x = '40e+8';
105*256a93a4Safresh1    my $y = $x;
106*256a93a4Safresh1    my $z = $y | 0;             # "|" also requires UV operands
107*256a93a4Safresh1    is($z, 4000000000, "string '$x' to UV conversion");
108*256a93a4Safresh1    ok(SvNOK($y), "string to UV conversion caches NV");
109*256a93a4Safresh1    ok(SvUOK(4000000000) ? SvUOK($y) : SvIOK_notUV($y),
110*256a93a4Safresh1       'string to UV conversion caches IV or UV');
111*256a93a4Safresh1    is($y ^ 0, 4000000000, 'reusing cached IV or UV');
112*256a93a4Safresh1}
113*256a93a4Safresh1
114*256a93a4Safresh1my $uv_max = ~0;
115*256a93a4Safresh1
116*256a93a4Safresh1{
117*256a93a4Safresh1    my $x = $uv_max * 7;        # Some large value not representable in IV/UV
118*256a93a4Safresh1    my $y = "$x";               # Convert to string
119*256a93a4Safresh1    my $z = $y << 0;
120*256a93a4Safresh1    is($z, $uv_max, 'large value in string is coerced to UV_MAX when UV is requested');
121*256a93a4Safresh1    ok(SvUOKp($y), 'converted UV is cached');
122*256a93a4Safresh1    is($y >> 0, $uv_max, 'reusing cached UV_MAX');
123*256a93a4Safresh1    my $v = $x << 0;            # Now NV to UV conversion
124*256a93a4Safresh1    is($v, $uv_max, 'large NV is coerced to UV_MAX when UV is requested');
125*256a93a4Safresh1    ok(SvUOKp($v), 'converted UV is cached');
126*256a93a4Safresh1    is($x >> 0, $uv_max, 'reusing cached UV_MAX');
127*256a93a4Safresh1}
128*256a93a4Safresh1
129*256a93a4Safresh1done_testing();
130