This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Make pack-as-int/sprintf-%c-ing/chr-ring inf/nan fatal.
[perl5.git] / t / op / infnan.t
index 17955e3..cc275d8 100644 (file)
@@ -32,111 +32,116 @@ my @NaN = ("NAN", "nan", "qnan", "SNAN", "NanQ", "NANS",
            "NaN123", "NAN(123)", "nan%",
            "nanonano"); # RIP, Robin Williams.
 
-my @num_fmt = qw(e f g a d u o b x p);
+my @printf_fmt = qw(e f g a d u o i b x p);
+my @packi_fmt = qw(a A Z b B h H c C s S l L i I n N v V j J w W p P u U);
+my @packf_fmt = qw(f d F);
 
-my $inf_tests = 13 + @num_fmt + 8 + 3 * @PInf + 3 * @NInf + 14 + 3;
-my $nan_tests =  8 + @num_fmt + 4 + 2 * @NaN + 14;
-
-my $infnan_tests = 13;
-
-plan tests => $inf_tests + 1 + $nan_tests + 1 + $infnan_tests + 1;
+if ($Config{ivsize} == 8) {
+    push @packi_fmt, qw(q Q);
+}
 
-print "# inf_tests    = $inf_tests\n";
-print "# nan_tests    = $nan_tests\n";
-print "# infnan_tests = $infnan_tests\n";
+if ($Config{uselongdouble}) {
+    push @packf_fmt, 'D';
+}
 
-my $has_inf;
-my $has_nan;
+# === Inf tests ===
 
-SKIP: {
-  if ($PInf == 0 && $NInf == 0) {
-    skip "no infinity found", $inf_tests;
-  }
+cmp_ok($PInf, '>', 0, "positive infinity");
+cmp_ok($NInf, '<', 0, "negative infinity");
 
-  $has_inf = 1;
+cmp_ok($PInf, '>', $NInf, "positive > negative");
+cmp_ok($NInf, '==', -$PInf, "negative == -positive");
+cmp_ok(-$NInf, '==', $PInf, "--negative == positive");
 
-  cmp_ok($PInf, '>', 0, "positive infinity");
-  cmp_ok($NInf, '<', 0, "negative infinity");
+is($PInf,  "Inf", "$PInf value stringifies as Inf");
+is($NInf, "-Inf", "$NInf value stringifies as -Inf");
 
-  cmp_ok($PInf, '>', $NInf, "positive > negative");
-  cmp_ok($NInf, '==', -$PInf, "negative == -positive");
-  cmp_ok(-$NInf, '==', $PInf, "--negative == positive");
+cmp_ok($PInf * 2, '==', $PInf, "twice Inf is Inf");
+cmp_ok($PInf / 2, '==', $PInf, "half of Inf is Inf");
 
-  is($PInf,  "Inf", "$PInf value stringifies as Inf");
-  is($NInf, "-Inf", "$NInf value stringifies as -Inf");
+cmp_ok($PInf + 1, '==', $PInf, "Inf + one is Inf");
+cmp_ok($NInf + 1, '==', $NInf, "-Inf + one is -Inf");
 
-  cmp_ok($PInf * 2, '==', $PInf, "twice Inf is Inf");
-  cmp_ok($PInf / 2, '==', $PInf, "half of Inf is Inf");
+is(sprintf("%g", $PInf), "Inf", "$PInf sprintf %g is Inf");
+is(sprintf("%a", $PInf), "Inf", "$PInf sprintf %a is Inf");
 
-  cmp_ok($PInf + 1, '==', $PInf, "Inf + one is Inf");
-  cmp_ok($NInf + 1, '==', $NInf, "-Inf + one is -Inf");
+for my $f (@printf_fmt) {
+    is(sprintf("%$f", $PInf), "Inf", "$PInf sprintf %$f is Inf");
+}
 
-  is(sprintf("%g", $PInf), "Inf", "$PInf sprintf %g is Inf");
-  is(sprintf("%a", $PInf), "Inf", "$PInf sprintf %a is Inf");
+ok(!defined eval { $a = sprintf("%c", $PInf)}, "sprintf %c +Inf undef");
+like($@, qr/Cannot printf/, "$PInf sprintf fails");
 
-  for my $f (@num_fmt) {
-      is(sprintf("%$f", $PInf), "Inf", "$PInf sprintf %$f is Inf");
-  }
+ok(!defined eval { $a = chr($PInf) }, "chr(+Inf) undef");
+like($@, qr/Cannot chr/, "+Inf chr() fails");
 
-  {
-      local $^W = 0;
+ok(!defined eval { $a = sprintf("%c", $NInf)}, "sprintf %c -Inf undef");
+like($@, qr/Cannot printf/, "$NInf sprintf fails");
 
-      is(sprintf("%c", $PInf), chr(0xFFFD), "$PInf sprintf %c is Inf");
-      is(chr($PInf), chr(0xFFFD), "$PInf chr() is U+FFFD");
+ok(!defined eval { $a = chr($NInf) }, "chr(-Inf) undef");
+like($@, qr/Cannot chr/, "-Inf chr() fails");
 
-      is(sprintf("%c", $NInf), chr(0xFFFD), "$NInf sprintf %c is Inf");
-      is(chr($NInf), chr(0xFFFD), "$NInf chr() is U+FFFD");
+for my $f (@packi_fmt) {
+    ok(!defined eval { $a = pack($f, $PInf) }, "pack $f +Inf undef");
+    like($@, $f eq 'w' ? qr/Cannot compress Inf/: qr/Cannot pack Inf/,
+         "+Inf pack $f fails");
+    ok(!defined eval { $a = pack($f, $NInf) }, "pack $f -Inf undef");
+    like($@, $f eq 'w' ? qr/Cannot compress -Inf/: qr/Cannot pack -Inf/,
+         "-Inf pack $f fails");
+}
 
-      is(pack('C', $PInf), chr(0xFF), "$PInf pack C is 0xFF byte");
-      is(pack('c', $PInf), chr(0xFF), "$PInf pack c is 0xFF byte");
+for my $f (@packf_fmt) {
+    ok(defined eval { $a = pack($f, $PInf) }, "pack $f +Inf defined");
+    eval { $b = unpack($f, $a) };
+    cmp_ok($b, '==', $PInf, "pack $f +Inf equals $PInf");
 
-      is(pack('C', $NInf), chr(0xFF), "$NInf pack C is 0xFF byte");
-      is(pack('c', $NInf), chr(0xFF), "$NInf pack c is 0xFF byte");
-  }
+    ok(defined eval { $a = pack($f, $NInf) }, "pack $f -Inf defined");
+    eval { $b = unpack($f, $a) };
+    cmp_ok($b, '==', $NInf, "pack $f -Inf equals $NInf");
+}
 
-  for my $i (@PInf) {
+for my $i (@PInf) {
     cmp_ok($i + 0 , '==', $PInf, "$i is +Inf");
     cmp_ok($i, '>', 0, "$i is positive");
     is("@{[$i+0]}", "Inf", "$i value stringifies as Inf");
-  }
+}
 
-  for my $i (@NInf) {
+for my $i (@NInf) {
     cmp_ok($i + 0, '==', $NInf, "$i is -Inf");
     cmp_ok($i, '<', 0, "$i is negative");
     is("@{[$i+0]}", "-Inf", "$i value stringifies as -Inf");
-  }
+}
 
-  is($PInf + $PInf, $PInf, "+inf plus +inf is +inf");
-  is($NInf + $NInf, $NInf, "-inf plus -inf is -inf");
+is($PInf + $PInf, $PInf, "+Inf plus +Inf is +Inf");
+is($NInf + $NInf, $NInf, "-Inf plus -Inf is -Inf");
 
-  is(1/$PInf, 0, "one per +Inf is zero");
-  is(1/$NInf, 0, "one per -Inf is zero");
+is(1/$PInf, 0, "one per +Inf is zero");
+is(1/$NInf, 0, "one per -Inf is zero");
 
-  my ($PInfPP, $PInfMM) = ($PInf, $PInf);
-  my ($NInfPP, $NInfMM) = ($NInf, $NInf);;
-  $PInfPP++;
-  $PInfMM--;
-  $NInfPP++;
-  $NInfMM--;
-  is($PInfPP, $PInf, "+inf++ is +inf");
-  is($PInfMM, $PInf, "+inf-- is +inf");
-  is($NInfPP, $NInf, "-inf++ is -inf");
-  is($NInfMM, $NInf, "-inf-- is -inf");
+my ($PInfPP, $PInfMM) = ($PInf, $PInf);
+my ($NInfPP, $NInfMM) = ($NInf, $NInf);;
+$PInfPP++;
+$PInfMM--;
+$NInfPP++;
+$NInfMM--;
+is($PInfPP, $PInf, "+Inf++ is +Inf");
+is($PInfMM, $PInf, "+Inf-- is +Inf");
+is($NInfPP, $NInf, "-Inf++ is -Inf");
+is($NInfMM, $NInf, "-Inf-- is -Inf");
 
-  ok($PInf, "+inf is true");
-  ok($NInf, "-inf is true");
+ok($PInf, "+Inf is true");
+ok($NInf, "-Inf is true");
 
-  is(sqrt($PInf), $PInf, "sqrt(+inf) is +inf");
-  is(exp($PInf), $PInf, "exp(+inf) is +inf");
-  is(exp($NInf), 0, "exp(-inf) is zero");
+is(sqrt($PInf), $PInf, "sqrt(+Inf) is +Inf");
+is(exp($PInf), $PInf, "exp(+Inf) is +Inf");
+is(exp($NInf), 0, "exp(-Inf) is zero");
 
- SKIP: {
-     my $here = "$^O $Config{osvers}";
-     if ($here =~ /^hpux 10/) {
-         skip "$here: pow doesn't generate Inf", 1;
-     }
-     is(9**9**9, $PInf, "9**9**9 is Inf");
-  }
+SKIP: {
+    my $here = "$^O $Config{osvers}";
+    if ($here =~ /^hpux 10/) {
+        skip "$here: pow doesn't generate Inf", 1;
+    }
+    is(9**9**9, $PInf, "9**9**9 is Inf");
 }
 
 SKIP: {
@@ -151,105 +156,99 @@ SKIP: {
     }
 }
 
-is(curr_test() - 1, $inf_tests, "expected number of inf tests");
+# === NaN ===
 
-SKIP: {
-  if ($NaN == 0) {
-    skip "no nan found", $nan_tests;
-  }
-
-  $has_nan = 1;
+cmp_ok($NaN, '!=', $NaN, "NaN is NaN numerically (by not being NaN)");
+ok($NaN eq $NaN, "NaN is NaN stringifically");
 
-  cmp_ok($NaN, '!=', $NaN, "NaN is NaN numerically (by not being NaN)");
-  ok($NaN eq $NaN, "NaN is NaN stringifically");
+is("$NaN", "NaN", "$NaN value stringifies as NaN");
 
-  is("$NaN", "NaN", "$NaN value stringifies as NaN");
+is("+NaN" + 0, "NaN", "+NaN is NaN");
+is("-NaN" + 0, "NaN", "-NaN is NaN");
 
-  is("+NaN" + 0, "NaN", "+NaN is NaN");
-  is("-NaN" + 0, "NaN", "-NaN is NaN");
+is($NaN * 2, $NaN, "twice NaN is NaN");
+is($NaN / 2, $NaN, "half of NaN is NaN");
 
-  is($NaN * 2, $NaN, "twice NaN is NaN");
-  is($NaN / 2, $NaN, "half of NaN is NaN");
+is($NaN + 1, $NaN, "NaN + one is NaN");
 
-  is($NaN + 1, $NaN, "NaN + one is NaN");
+for my $f (@printf_fmt) {
+    is(sprintf("%$f", $NaN), "NaN", "$NaN sprintf %$f is NaN");
+}
 
-  for my $f (@num_fmt) {
-      is(sprintf("%$f", $NaN), "NaN", "$NaN sprintf %$f is NaN");
-  }
+ok(!defined eval { $a = sprintf("%c", $NaN)}, "sprintf %c NaN undef");
+like($@, qr/Cannot printf/, "$NaN sprintf fails");
 
-  {
-      local $^W = 0;
+ok(!defined eval { $a = chr($NaN) }, "chr NaN undef");
+like($@, qr/Cannot chr/, "NaN chr() fails");
 
-      is(sprintf("%c", $NaN), chr(0xFFFD), "$NaN sprintf %c is Inf");
-      is(chr($NaN), chr(0xFFFD), "$NaN chr() is U+FFFD");
+for my $f (@packi_fmt) {
+    ok(!defined eval { $a = pack($f, $NaN) }, "pack $f NaN undef");
+    like($@, $f eq 'w' ? qr/Cannot compress NaN/: qr/Cannot pack NaN/,
+         "NaN pack $f fails");
+}
 
-      is(pack('C', $NaN), chr(0xFF), "$NaN pack C is 0xFF byte");
-      is(pack('c', $NaN), chr(0xFF), "$NaN pack c is 0xFF");
-  }
+for my $f (@packf_fmt) {
+    ok(defined eval { $a = pack($f, $NaN) }, "pack $f NaN defined");
+    eval { $b = unpack($f, $a) };
+    cmp_ok($b, '!=', $b, "pack $f NaN not-equals $NaN");
+}
 
-  for my $i (@NaN) {
+for my $i (@NaN) {
     cmp_ok($i + 0, '!=', $i + 0, "$i is NaN numerically (by not being NaN)");
     is("@{[$i+0]}", "NaN", "$i value stringifies as NaN");
-  }
+}
 
-  ok(!($NaN <  0), "NaN is not lt zero");
-  ok(!($NaN == 0), "NaN is not == zero");
-  ok(!($NaN >  0), "NaN is not gt zero");
+ok(!($NaN <  0), "NaN is not lt zero");
+ok(!($NaN == 0), "NaN is not == zero");
+ok(!($NaN >  0), "NaN is not gt zero");
 
-  ok(!($NaN < $NaN), "NaN is not lt NaN");
-  ok(!($NaN > $NaN), "NaN is not gt NaN");
+ok(!($NaN < $NaN), "NaN is not lt NaN");
+ok(!($NaN > $NaN), "NaN is not gt NaN");
 
-  # is() okay with $NaN because it uses eq.
-  is($NaN * 0, $NaN, "NaN times zero is NaN");
-  is($NaN * 2, $NaN, "NaN times two is NaN");
+# is() okay with $NaN because it uses eq.
+is($NaN * 0, $NaN, "NaN times zero is NaN");
+is($NaN * 2, $NaN, "NaN times two is NaN");
 
-  my ($NaNPP, $NaNMM) = ($NaN, $NaN);
-  $NaNPP++;
-  $NaNMM--;
-  is($NaNPP, $NaN, "+inf++ is +inf");
-  is($NaNMM, $NaN, "+inf-- is +inf");
+my ($NaNPP, $NaNMM) = ($NaN, $NaN);
+$NaNPP++;
+$NaNMM--;
+is($NaNPP, $NaN, "+Inf++ is +Inf");
+is($NaNMM, $NaN, "+Inf-- is +Inf");
 
-  ok($NaN, "NaN is true");
+# You might find this surprising (isn't NaN kind of like of undef?)
+# but this is how it is.
+ok($NaN, "NaN is true");
 
-  is(sqrt($NaN), $NaN, "sqrt(nan) is nan");
-  is(exp($NaN), $NaN, "exp(nan) is nan");
-  is(sin($NaN), $NaN, "sin(nan) is nan");
+is(sqrt($NaN), $NaN, "sqrt(NaN) is NaN");
+is(exp($NaN), $NaN, "exp(NaN) is NaN");
+is(sin($NaN), $NaN, "sin(NaN) is NaN");
 
- SKIP: {
-     my $here = "$^O $Config{osvers}";
-     if ($here =~ /^hpux 10/) {
-         skip "$here: pow doesn't generate Inf, so sin(Inf) won't happen", 1;
-     }
-     is(sin(9**9**9), $NaN, "sin(9**9**9) is NaN");
-  }
+SKIP: {
+    my $here = "$^O $Config{osvers}";
+    if ($here =~ /^hpux 10/) {
+        skip "$here: pow doesn't generate Inf, so sin(Inf) won't happen", 1;
+    }
+    is(sin(9**9**9), $NaN, "sin(9**9**9) is NaN");
 }
 
-is(curr_test() - 1, $inf_tests + 1 + $nan_tests,
-   "expected number of nan tests");
+# === Tests combining Inf and NaN ===
 
-SKIP: {
-  unless ($has_inf && $has_nan) {
-    skip "no both Inf and Nan", $infnan_tests;
-  }
+# is() okay with $NaN because it uses eq.
+is($PInf * 0,     $NaN, "Inf times zero is NaN");
+is($PInf * $NaN,  $NaN, "Inf times NaN is NaN");
+is($PInf + $NaN,  $NaN, "Inf plus NaN is NaN");
+is($PInf - $PInf, $NaN, "Inf minus inf is NaN");
+is($PInf / $PInf, $NaN, "Inf div inf is NaN");
+is($PInf % $PInf, $NaN, "Inf mod inf is NaN");
 
-  # is() okay with $NaN because it uses eq.
-  is($PInf * 0,     $NaN, "Inf times zero is NaN");
-  is($PInf * $NaN,  $NaN, "Inf times NaN is NaN");
-  is($PInf + $NaN,  $NaN, "Inf plus NaN is NaN");
-  is($PInf - $PInf, $NaN, "Inf minus inf is NaN");
-  is($PInf / $PInf, $NaN, "Inf div inf is NaN");
-  is($PInf % $PInf, $NaN, "Inf mod inf is NaN");
+ok(!($NaN <  $PInf), "NaN is not lt +Inf");
+ok(!($NaN == $PInf), "NaN is not eq +Inf");
+ok(!($NaN >  $PInf), "NaN is not gt +Inf");
 
-  ok(!($NaN <  $PInf), "NaN is not lt +inf");
-  ok(!($NaN == $PInf), "NaN is not eq +inf");
-  ok(!($NaN >  $PInf), "NaN is not gt +inf");
+ok(!($NaN >  $NInf), "NaN is not lt -Inf");
+ok(!($NaN == $NInf), "NaN is not eq -Inf");
+ok(!($NaN <  $NInf), "NaN is not gt -Inf");
 
-  ok(!($NaN >  $NInf), "NaN is not lt -inf");
-  ok(!($NaN == $NInf), "NaN is not eq -inf");
-  ok(!($NaN <  $NInf), "NaN is not gt -inf");
-
-  is(sin($PInf), $NaN, "sin(+inf) is nan");
-}
+is(sin($PInf), $NaN, "sin(+Inf) is NaN");
 
-is(curr_test() - 1, $inf_tests + 1 + $nan_tests + 1 + $infnan_tests,
-   "expected number of nan tests");
+done_testing();