1#!./perl 2 3BEGIN { 4 chdir 't' if -d 't'; 5 require './test.pl'; 6 set_up_inc('../lib'); 7} 8 9use v5.36; 10no warnings 'experimental::builtin'; 11 12package FetchStoreCounter { 13 sub TIESCALAR($class, @args) { bless \@args, $class } 14 15 sub FETCH($self) { $self->[0]->$*++ } 16 sub STORE($self, $) { $self->[1]->$*++ } 17} 18 19# booleans 20{ 21 use builtin qw( true false is_bool ); 22 23 ok(true, 'true is true'); 24 ok(!false, 'false is false'); 25 26 ok(is_bool(true), 'true is bool'); 27 ok(is_bool(false), 'false is bool'); 28 ok(!is_bool(undef), 'undef is not bool'); 29 ok(!is_bool(1), '1 is not bool'); 30 ok(!is_bool(""), 'empty is not bool'); 31 32 my $truevar = (5 == 5); 33 my $falsevar = (5 == 6); 34 35 ok(is_bool($truevar), '$truevar is bool'); 36 ok(is_bool($falsevar), '$falsevar is bool'); 37 38 ok(is_bool(is_bool(true)), 'is_bool true is bool'); 39 ok(is_bool(is_bool(123)), 'is_bool false is bool'); 40 41 # Invokes magic 42 43 tie my $tied, FetchStoreCounter => (\my $fetchcount, \my $storecount); 44 45 my $_dummy = is_bool($tied); 46 is($fetchcount, 1, 'is_bool() invokes FETCH magic'); 47 48 $tied = is_bool(false); 49 is($storecount, 1, 'is_bool() invokes STORE magic'); 50 51 is(prototype(\&builtin::is_bool), '$', 'is_bool prototype'); 52} 53 54# float constants 55{ 56 use builtin qw( inf nan ); 57 58 ok(inf, 'inf is true'); 59 ok(inf > 1E10, 'inf is bigger than 1E10'); 60 ok(inf == inf, 'inf is equal to inf'); 61 ok(inf == inf + 1, 'inf is equal to inf + 1'); 62 63 # Invoke the real XSUB 64 my $inf = ( \&builtin::inf )->(); 65 ok($inf == $inf + 1, 'inf returned by real xsub'); 66 67 ok(nan != nan, 'NaN is not equal to NaN'); 68 69 my $nan = ( \&builtin::nan )->(); 70 ok($nan != $nan, 'NaN returned by real xsub'); 71} 72 73# weakrefs 74{ 75 use builtin qw( is_weak weaken unweaken ); 76 77 my $arr = []; 78 my $ref = $arr; 79 80 ok(!is_weak($ref), 'ref is not weak initially'); 81 82 weaken($ref); 83 ok(is_weak($ref), 'ref is weak after weaken()'); 84 85 unweaken($ref); 86 ok(!is_weak($ref), 'ref is not weak after unweaken()'); 87 88 weaken($ref); 89 undef $arr; 90 is($ref, undef, 'ref is now undef after arr is cleared'); 91 92 is(prototype(\&builtin::weaken), '$', 'weaken prototype'); 93 is(prototype(\&builtin::unweaken), '$', 'unweaken prototype'); 94 is(prototype(\&builtin::is_weak), '$', 'is_weak prototype'); 95} 96 97# reference queries 98{ 99 use builtin qw( refaddr reftype blessed ); 100 101 my $arr = []; 102 my $obj = bless [], "Object"; 103 104 is(refaddr($arr), $arr+0, 'refaddr yields same as ref in numeric context'); 105 is(refaddr("not a ref"), undef, 'refaddr yields undef for non-reference'); 106 107 is(reftype($arr), "ARRAY", 'reftype yields type string'); 108 is(reftype($obj), "ARRAY", 'reftype yields basic container type for blessed object'); 109 is(reftype("not a ref"), undef, 'reftype yields undef for non-reference'); 110 111 is(blessed($arr), undef, 'blessed yields undef for non-object'); 112 is(blessed($obj), "Object", 'blessed yields package name for object'); 113 114 # blessed() as a boolean 115 is(blessed($obj) ? "YES" : "NO", "YES", 'blessed in boolean context still works'); 116 117 # blessed() appears false as a boolean on package "0" 118 is(blessed(bless [], "0") ? "YES" : "NO", "NO", 'blessed in boolean context handles "0" cornercase'); 119 120 is(prototype(\&builtin::blessed), '$', 'blessed prototype'); 121 is(prototype(\&builtin::refaddr), '$', 'refaddr prototype'); 122 is(prototype(\&builtin::reftype), '$', 'reftype prototype'); 123} 124 125# created_as_... 126{ 127 use builtin qw( created_as_string created_as_number ); 128 129 # some literal constants 130 ok(!created_as_string(undef), 'undef created as !string'); 131 ok(!created_as_number(undef), 'undef created as !number'); 132 133 ok( created_as_string("abc"), 'abc created as string'); 134 ok(!created_as_number("abc"), 'abc created as number'); 135 136 ok(!created_as_string(123), '123 created as !string'); 137 ok( created_as_number(123), '123 created as !number'); 138 139 ok(!created_as_string(1.23), '1.23 created as !string'); 140 ok( created_as_number(1.23), '1.23 created as !number'); 141 142 ok(!created_as_string([]), '[] created as !string'); 143 ok(!created_as_number([]), '[] created as !number'); 144 145 ok(!created_as_string(builtin::true), 'true created as !string'); 146 ok(!created_as_number(builtin::true), 'true created as !number'); 147 148 ok(builtin::is_bool(created_as_string(0)), 'created_as_string returns bool'); 149 ok(builtin::is_bool(created_as_number(0)), 'created_as_number returns bool'); 150 151 # variables 152 my $just_pv = "def"; 153 ok( created_as_string($just_pv), 'def created as string'); 154 ok(!created_as_number($just_pv), 'def created as number'); 155 156 my $just_iv = 456; 157 ok(!created_as_string($just_iv), '456 created as string'); 158 ok( created_as_number($just_iv), '456 created as number'); 159 160 my $just_nv = 4.56; 161 ok(!created_as_string($just_nv), '456 created as string'); 162 ok( created_as_number($just_nv), '456 created as number'); 163 164 # variables reused 165 my $originally_pv = "1"; 166 my $pv_as_iv = $originally_pv + 0; 167 ok( created_as_string($originally_pv), 'PV reused as IV created as string'); 168 ok(!created_as_number($originally_pv), 'PV reused as IV created as !number'); 169 ok(!created_as_string($pv_as_iv), 'New number from PV created as !string'); 170 ok( created_as_number($pv_as_iv), 'New number from PV created as number'); 171 172 my $originally_iv = 1; 173 my $iv_as_pv = "$originally_iv"; 174 ok(!created_as_string($originally_iv), 'IV reused as PV created as !string'); 175 ok( created_as_number($originally_iv), 'IV reused as PV created as number'); 176 ok( created_as_string($iv_as_pv), 'New string from IV created as string'); 177 ok(!created_as_number($iv_as_pv), 'New string from IV created as !number'); 178 179 my $originally_nv = 1.1; 180 my $nv_as_pv = "$originally_nv"; 181 ok(!created_as_string($originally_nv), 'NV reused as PV created as !string'); 182 ok( created_as_number($originally_nv), 'NV reused as PV created as number'); 183 ok( created_as_string($nv_as_pv), 'New string from NV created as string'); 184 ok(!created_as_number($nv_as_pv), 'New string from NV created as !number'); 185 186 # magic 187 local $1; 188 "hello" =~ m/(.*)/; 189 ok(created_as_string($1), 'magic string'); 190 191 is(prototype(\&builtin::created_as_string), '$', 'created_as_string prototype'); 192 is(prototype(\&builtin::created_as_number), '$', 'created_as_number prototype'); 193} 194 195# stringify 196{ 197 use builtin qw( stringify ); 198 199 is(stringify("abc"), "abc", 'stringify a plain string'); 200 is(stringify(123), "123", 'stringify a number'); 201 202 my $aref = []; 203 is(stringify($aref), "$aref", 'stringify an array ref'); 204 205 use builtin qw( created_as_string ); 206 ok(!ref stringify($aref), 'stringified arrayref is not a ref'); 207 ok(created_as_string(stringify($aref)), 'stringified arrayref is created as string'); 208 209 package WithOverloadedStringify { 210 use overload '""' => sub { return "STRING" }; 211 } 212 213 is(stringify(bless [], "WithOverloadedStringify"), "STRING", 'stringify invokes "" overload'); 214} 215 216# ceil, floor 217{ 218 use builtin qw( ceil floor ); 219 220 cmp_ok(ceil(1.5), '==', 2, 'ceil(1.5) == 2'); 221 cmp_ok(floor(1.5), '==', 1, 'floor(1.5) == 1'); 222 223 # Invokes magic 224 225 tie my $tied, FetchStoreCounter => (\my $fetchcount, \my $storecount); 226 227 my $_dummy = ceil($tied); 228 is($fetchcount, 1, 'ceil() invokes FETCH magic'); 229 230 $tied = ceil(1.1); 231 is($storecount, 1, 'ceil() TARG invokes STORE magic'); 232 233 $fetchcount = $storecount = 0; 234 tie $tied, FetchStoreCounter => (\$fetchcount, \$storecount); 235 236 $_dummy = floor($tied); 237 is($fetchcount, 1, 'floor() invokes FETCH magic'); 238 239 $tied = floor(1.1); 240 is($storecount, 1, 'floor() TARG invokes STORE magic'); 241 242 is(prototype(\&builtin::ceil), '$', 'ceil prototype'); 243 is(prototype(\&builtin::floor), '$', 'floor prototype'); 244} 245 246# imports are lexical; should not be visible here 247{ 248 my $ok = eval 'true()'; my $e = $@; 249 ok(!$ok, 'true() not visible outside of lexical scope'); 250 like($e, qr/^Undefined subroutine &main::true called at /, 'failure from true() not visible'); 251} 252 253# lexical imports work fine in a variety of situations 254{ 255 sub regularfunc { 256 use builtin 'true'; 257 return true; 258 } 259 ok(regularfunc(), 'true in regular sub'); 260 261 my sub lexicalfunc { 262 use builtin 'true'; 263 return true; 264 } 265 ok(lexicalfunc(), 'true in lexical sub'); 266 267 my $coderef = sub { 268 use builtin 'true'; 269 return true; 270 }; 271 ok($coderef->(), 'true in anon sub'); 272 273 sub recursefunc { 274 use builtin 'true'; 275 return recursefunc() if @_; 276 return true; 277 } 278 ok(recursefunc("rec"), 'true in self-recursive sub'); 279 280 my sub recurselexicalfunc { 281 use builtin 'true'; 282 return __SUB__->() if @_; 283 return true; 284 } 285 ok(recurselexicalfunc("rec"), 'true in self-recursive lexical sub'); 286 287 my $recursecoderef = sub { 288 use builtin 'true'; 289 return __SUB__->() if @_; 290 return true; 291 }; 292 ok($recursecoderef->("rec"), 'true in self-recursive anon sub'); 293} 294 295{ 296 use builtin qw( true false ); 297 298 my $val = true; 299 cmp_ok($val, $_, !!1, "true is equivalent to !!1 by $_") for qw( eq == ); 300 cmp_ok($val, $_, !0, "true is equivalent to !0 by $_") for qw( eq == ); 301 302 $val = false; 303 cmp_ok($val, $_, !!0, "false is equivalent to !!0 by $_") for qw( eq == ); 304 cmp_ok($val, $_, !1, "false is equivalent to !1 by $_") for qw( eq == ); 305} 306 307# indexed 308{ 309 use builtin qw( indexed ); 310 311 # We don't have Test::More's is_deeply here 312 313 ok(eq_array([indexed], [] ), 314 'indexed on empty list'); 315 316 ok(eq_array([indexed "A"], [0, "A"] ), 317 'indexed on singleton list'); 318 319 ok(eq_array([indexed "X" .. "Z"], [0, "X", 1, "Y", 2, "Z"] ), 320 'indexed on 3-item list'); 321 322 my @orig = (1..3); 323 $_++ for indexed @orig; 324 ok(eq_array(\@orig, [1 .. 3]), 'indexed copies values, does not alias'); 325 326 { 327 my $ok = 1; 328 foreach my ($len, $s) (indexed "", "x", "xx") { 329 length($s) == $len or undef $ok; 330 } 331 ok($ok, 'indexed operates nicely with multivar foreach'); 332 } 333 334 { 335 my %hash = indexed "a" .. "e"; 336 ok(eq_hash(\%hash, { 0 => "a", 1 => "b", 2 => "c", 3 => "d", 4 => "e" }), 337 'indexed can be used to create hashes'); 338 } 339 340 { 341 no warnings 'scalar'; 342 343 my $count = indexed 'i', 'ii', 'iii', 'iv'; 344 is($count, 8, 'indexed in scalar context yields size of list it would return'); 345 } 346 347 is(prototype(\&builtin::indexed), '@', 'indexed prototype'); 348} 349 350# Vanilla trim tests 351{ 352 use builtin qw( trim ); 353 354 is(trim(" Hello world! ") , "Hello world!" , 'trim spaces'); 355 is(trim("\tHello world!\t") , "Hello world!" , 'trim tabs'); 356 is(trim("\n\n\nHello\nworld!\n") , "Hello\nworld!" , 'trim \n'); 357 is(trim("\t\n\n\nHello world!\n \t"), "Hello world!" , 'trim all three'); 358 is(trim("Perl") , "Perl" , 'trim nothing'); 359 is(trim('') , "" , 'trim empty string'); 360 361 is(prototype(\&builtin::trim), '$', 'trim prototype'); 362} 363 364TODO: { 365 my $warn = ''; 366 local $SIG{__WARN__} = sub { $warn .= join "", @_; }; 367 368 is(builtin::trim(undef), "", 'trim undef'); 369 like($warn , qr/^Use of uninitialized value in subroutine entry at/, 370 'trim undef triggers warning'); 371 local $main::TODO = "Currently uses generic value for the name of non-opcode builtins"; 372 like($warn , qr/^Use of uninitialized value in trim at/, 373 'trim undef triggers warning using actual name of builtin'); 374} 375 376# Fancier trim tests against a regexp and unicode 377{ 378 use builtin qw( trim ); 379 my $nbsp = chr utf8::unicode_to_native(0xA0); 380 381 is(trim(" \N{U+2603} "), "\N{U+2603}", 'trim with unicode content'); 382 is(trim("\N{U+2029}foobar\x{2028} "), "foobar", 383 'trim with unicode whitespace'); 384 is(trim("$nbsp foobar$nbsp "), "foobar", 'trim with latin1 whitespace'); 385} 386 387# Test on a magical fetching variable 388{ 389 use builtin qw( trim ); 390 391 my $str3 = " Hello world!\t"; 392 $str3 =~ m/(.+Hello)/; 393 is(trim($1), "Hello", "trim on a magical variable"); 394} 395 396# Inplace edit, my, our variables 397{ 398 use builtin qw( trim ); 399 400 my $str4 = "\t\tHello world!\n\n"; 401 $str4 = trim($str4); 402 is($str4, "Hello world!", "trim on an inplace variable"); 403 404 our $str2 = "\t\nHello world!\t "; 405 is(trim($str2), "Hello world!", "trim on an our \$var"); 406} 407 408# Lexical export 409{ 410 my $name; 411 BEGIN { 412 use builtin qw( export_lexically ); 413 414 $name = "message"; 415 export_lexically $name => sub { "Hello, world" }; 416 } 417 418 is(message(), "Hello, world", 'Lexically exported sub is callable'); 419 ok(!__PACKAGE__->can("message"), 'Exported sub is not visible via ->can'); 420 421 is($name, "message", '$name argument was not modified by export_lexically'); 422 423 our ( $scalar, @array, %hash ); 424 BEGIN { 425 use builtin qw( export_lexically ); 426 427 export_lexically 428 '$SCALAR' => \$scalar, 429 '@ARRAY' => \@array, 430 '%HASH' => \%hash; 431 } 432 433 $::scalar = "value"; 434 is($SCALAR, "value", 'Lexically exported scalar is accessible'); 435 436 @::array = ('a' .. 'e'); 437 is(scalar @ARRAY, 5, 'Lexically exported array is accessible'); 438 439 %::hash = (key => "val"); 440 is($HASH{key}, "val", 'Lexically exported hash is accessible'); 441} 442 443# load_module 444{ 445 use builtin qw( load_module ); 446 use feature qw( try ); 447 my ($ok, $e); 448 449 # Can't really test this sans string eval, as it's a compilation error: 450 eval 'load_module();'; 451 $e = $@; 452 ok($e, 'load_module(); fails'); 453 like($e, qr/^Not enough arguments for builtin::load_module at/, 'load_module(); fails with correct error'); 454 eval 'load_module;'; 455 $e = $@; 456 ok($e, 'load_module; fails'); 457 like($e, qr/^Not enough arguments for builtin::load_module at/, 'load_module; fails with correct error'); 458 459 # Failure to load module croaks 460 try { 461 load_module(undef); 462 } catch ($e) { 463 ok($e, 'load_module(undef) fails'); 464 like($e, qr/^Usage: builtin::load_module\(defined string\)/, 'load_module(undef) fails with correct error'); 465 }; 466 try { 467 load_module(\"Foo"); 468 } catch ($e) { 469 ok($e, 'load_module(\"Foo") fails'); 470 like($e, qr/^Usage: builtin::load_module\(defined string\)/, 'load_module(\"Foo") fails with correct error'); 471 }; 472 try { 473 load_module(["Foo"]); 474 } catch ($e) { 475 ok($e, 'load_module(["Foo"]) fails'); 476 like($e, qr/^Usage: builtin::load_module\(defined string\)/, 'load_module(["Foo"]) fails with correct error'); 477 }; 478 try { 479 load_module('5.36'); 480 } 481 catch ($e) { 482 ok($e, 'load_module("5.36") fails'); 483 like($e, qr/^Can't locate 5[.]36[.]pm in \@INC/, 'load_module("5.36") fails with correct error'); 484 }; 485 try { 486 load_module('v5.36'); 487 } 488 catch ($e) { 489 ok($e, 'load_module("v5.36") fails'); 490 like($e, qr/^Can't locate v5[.]36[.]pm in \@INC/, 'load_module("v5.36") fails with correct error'); 491 }; 492 try { 493 load_module("Dies"); 494 fail('load_module("Dies") succeeded!'); 495 } 496 catch ($e) { 497 ok($e, 'load_module("Dies") fails'); 498 like($e, qr/^Can't locate Dies[.]pm in \@INC/, 'load_module("Dies") fails with correct error'); 499 } 500 my $module_name = 'Dies'; 501 try { 502 load_module($module_name); 503 fail('load_module($module_name) $module_name=Dies succeeded!'); 504 } 505 catch ($e) { 506 ok($e, 'load_module($module_name) $module_name=Dies fails'); 507 like($e, qr/^Can't locate Dies[.]pm in \@INC/, 'load_module($module_name) $module_name=Dies fails with correct error'); 508 } 509 $module_name =~ m!(\w+)!; 510 try { 511 load_module($1); 512 fail('load_module($1) from $module_name=Dies succeeded!'); 513 } 514 catch ($e) { 515 ok($e, 'load_module($1) from $module_name=Dies fails'); 516 like($e, qr/^Can't locate Dies[.]pm in \@INC/, 'load_module($1) from $module_name=Dies fails with correct error'); 517 } 518 "Dies" =~ m!(\w+)!; 519 try { 520 load_module($1); 521 fail('load_module($1) from "Dies" succeeded!'); 522 } 523 catch ($e) { 524 ok($e, 'load_module($1) from "Dies" fails'); 525 like($e, qr/^Can't locate Dies[.]pm in \@INC/, 'load_module($1) from "Dies" fails with correct error'); 526 } 527 528 # Loading module goes well 529 my $ret; 530 try { 531 $ret = load_module("strict"); 532 pass('load_module("strict") worked'); 533 is($ret, "strict", 'load_module("strict") returned "strict"'); 534 } 535 catch ($e) { 536 fail('load_module("strict") errored: ' . $e); 537 } 538 $module_name = 'strict'; 539 try { 540 $ret = load_module($module_name); 541 pass('load_module($module_name) $module_name=strict worked'); 542 is($ret, "strict", 'load_module($module_name) returned "strict"'); 543 } 544 catch ($e) { 545 fail('load_module($module_name) $module_name=strict errored: ' . $e); 546 } 547 $module_name =~ m!(\w+)!; 548 try { 549 $ret = load_module($1); 550 pass('load_module($1) from $module_name=strict worked'); 551 is($ret, "strict", 'load_module($1) from $module_name=strict returned "strict"'); 552 } 553 catch ($e) { 554 fail('load_module($1) from $module_name=strict errored: ' . $e); 555 } 556 "strict" =~ m!(\w+)!; 557 try { 558 $ret = load_module($1); 559 pass('load_module($1) from "strict" worked'); 560 is($ret, "strict", 'load_module($1) from "strict" returned "strict"'); 561 } 562 catch ($e) { 563 fail('load_module($1) from "strict" errored: ' . $e); 564 } 565 566 # Slightly more complex, based on tie 567 { 568 package BuiltinTestTie { 569 sub TIESCALAR { 570 bless $_[1], $_[0]; 571 } 572 sub FETCH { 573 ${$_[0]} 574 } 575 } 576 my $x; 577 tie my $y, BuiltinTestTie => \$x; 578 $x = "strict"; 579 try { 580 $ret = load_module($y); 581 pass('load_module($y) from $y tied to $x=strict worked'); 582 is($ret, "strict", 'load_module($y) from $y tied to $x=strict worked and returned "strict"'); 583 } 584 catch ($e) { 585 fail('load_module($y) from $y tied to $x=strict failed: ' . $e); 586 }; 587 } 588 589 # Can be used to import a symbol to the current namespace, too: 590 { 591 my $aref = []; 592 my $aref_stringified = "$aref"; 593 my $got = eval ' 594 BEGIN { 595 load_module("builtin")->import("stringify"); 596 } 597 stringify($aref); 598 '; 599 if (my $error = $@) { 600 fail('load_module("builtin")->import("stringify") failed: ' . $error); 601 } 602 is($got, $aref_stringified, 'load_module("builtin")->import("stringify") works, stringifying $aref'); 603 } 604} 605 606# version bundles 607{ 608 use builtin ':5.39'; 609 ok(true, 'true() is available from :5.39 bundle'); 610 611 # parse errors 612 foreach my $bundle (qw( :x :5.x :5.36x :5.36.1000 :5.1000 :5.36.1.2 ), 613 ": +5.+39", ": +5.+40. -10", ": 5.40", ":5 .40", ":5.+40", 614 ":5.40 .0", ":5.40.-10", ":5.40\0") { 615 (my $pretty_bundle = $bundle) =~ s/([^[:print:]])/ sprintf("\\%o", ord $1) /ge; 616 ok(!defined eval "use builtin '$bundle';", $pretty_bundle.' is invalid bundle'); 617 like($@, qr/^Invalid version bundle "\Q$pretty_bundle\E" at /); 618 } 619} 620 621# github #21981 622{ 623 fresh_perl_is(<<'EOS', "", {}, "github 21981: panic in intro_my"); 624use B; 625BEGIN { B::save_BEGINs; } 626use v5.39; 627EOS 628} 629 630# github #22542 631{ 632 # some of these functions don't error at this point, but they might be updated 633 # and see the same problem we fix here 634 for my $func (qw(is_bool is_weak blessed refaddr reftype ceil floor is_tainted 635 trim stringify created_as_string created_as_number)) { 636 my $arg = 637 $func =~ /ceil|floor|created_as/ ? "1.1" : 638 $func =~ /(^ref|blessed|is_weak)/ ? "\\1" : '"abc"'; 639 fresh_perl_is(<<"EOS", "ok", {}, "goto $func"); 640no warnings "experimental"; 641sub f { goto &builtin::$func } 642f($arg); 643print "ok"; 644EOS 645 } 646} 647 648# vim: tabstop=4 shiftwidth=4 expandtab autoindent softtabstop=4 649 650done_testing(); 651