1#! /usr/bin/python 2# 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2018-2023 Gavin D. Howard and contributors. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions are met: 9# 10# * Redistributions of source code must retain the above copyright notice, this 11# list of conditions and the following disclaimer. 12# 13# * Redistributions in binary form must reproduce the above copyright notice, 14# this list of conditions and the following disclaimer in the documentation 15# and/or other materials provided with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import os, sys 31import time 32import signal 33import traceback 34 35try: 36 import pexpect 37except ImportError: 38 print("Could not find pexpect. Skipping...") 39 sys.exit(0) 40 41# Housekeeping. 42script = sys.argv[0] 43testdir = os.path.dirname(script) 44 45if "BC_TEST_OUTPUT_DIR" in os.environ: 46 outputdir = os.environ["BC_TEST_OUTPUT_DIR"] 47else: 48 outputdir = testdir 49 50prompt = ">>> " 51 52# This array is for escaping characters that are necessary to escape when 53# outputting to pexpect. Since pexpect takes regexes, these characters confuse 54# it unless we escape them. 55escapes = [ 56 ']', 57 '[', 58 '+', 59] 60 61# UTF-8 stress tests. 62utf8_stress1 = "ᆬḰ䋔䗅㜲ತ咡䒢岤䳰稨⣡嶣㷡嶏ⵐ䄺嵕ਅ奰痚㆜䊛拂䅙૩➋䛿ቬ竳Ϳᅠ❄产翷䮊௷Ỉ䷒䳜㛠➕傎ᗋᏯਕ䆐悙癐㺨" 63utf8_stress2 = "韠싧돳넨큚ꉿ뮴픷ꉲ긌�최릙걆鳬낽ꪁ퍼鈴핐黙헶ꪈ뮩쭀锻끥鉗겉욞며뛯�ﻼ�度錐�" 64utf8_stress3 = "곻�䣹昲蜴Ὓ桢㎏⚦珢畣갴ﭱ鶶ๅ뀁彻ꖒ䔾ꢚﱤ햔햞㐹�鼳뵡▿ⶾ꠩�纞⊐佧�ⵟ霘紳㱔籠뎼⊓搧硤" 65utf8_stress4 = "ᄀ��" 66 67# An easy array for UTF-8 tests. 68utf8_stress_strs = [ 69 utf8_stress1, 70 utf8_stress2, 71 utf8_stress3, 72 utf8_stress4, 73] 74 75 76def expect(child, data): 77 child.expect(data) 78 79 80# Eats all of the child's data. 81# @param child The child whose data should be eaten. 82def eat(child): 83 while child.buffer is not None and len(child.buffer) > 0: 84 expect(child, ".+") 85 86 87# Send data to a child. This makes sure the buffers are empty first. 88# @param child The child to send data to. 89# @param data The data to send. 90def send(child, data): 91 eat(child) 92 child.send(data) 93 94 95def wait(child): 96 if child.isalive(): 97 child.sendeof() 98 time.sleep(1) 99 if child.isalive(): 100 child.kill(signal.SIGTERM) 101 time.sleep(1) 102 if child.isalive(): 103 child.kill(signal.SIGKILL) 104 child.wait() 105 106 107# Check that the child output the expected line. If history is false, then 108# the output should change. 109def check_line(child, expected, prompt=">>> ", history=True): 110 send(child, "\n") 111 prefix = "\r\n" if history else "" 112 expect(child, prefix + expected + "\r\n" + prompt) 113 114 115# Write a string to output, checking all of the characters are output, 116# one-by-one. 117def write_str(child, s): 118 for c in s: 119 send(child, c) 120 if c in escapes: 121 expect(child, "\\{}".format(c)) 122 else: 123 expect(child, c) 124 125 126# Check the bc banner. 127# @param child The child process. 128def bc_banner(child): 129 bc_banner1 = "bc [0-9]+\.[0-9]+\.[0-9]+\r\n" 130 bc_banner2 = "Copyright \(c\) 2018-[2-9][0-9][0-9][0-9] Gavin D. Howard and contributors\r\n" 131 bc_banner3 = "Report bugs at: https://git.gavinhoward.com/gavin/bc\r\n\r\n" 132 bc_banner4 = "This is free software with ABSOLUTELY NO WARRANTY.\r\n\r\n" 133 expect(child, bc_banner1) 134 expect(child, bc_banner2) 135 expect(child, bc_banner3) 136 expect(child, bc_banner4) 137 expect(child, prompt) 138 139 140# Common UTF-8 testing function. The index is the index into utf8_stress_strs 141# for which stress string to use. 142# @param exe The executable. 143# @param args The arguments to pass to the executable. 144# @param env The environment. 145# @param idx The index of the UTF-8 stress string. 146def test_utf8(exe, args, env, idx, bc=True): 147 148 # Because both bc and dc use this, make sure the banner doesn't pop. 149 env["BC_BANNER"] = "0" 150 151 child = pexpect.spawn(exe, args=args, env=env, encoding='utf-8', codec_errors='ignore') 152 153 try: 154 155 # Write the stress string. 156 send(child, utf8_stress_strs[idx]) 157 send(child, "\n") 158 159 if bc: 160 send(child, "quit") 161 else: 162 send(child, "q") 163 164 send(child, "\n") 165 166 wait(child) 167 168 except pexpect.TIMEOUT: 169 traceback.print_tb(sys.exc_info()[2]) 170 print("timed out") 171 print(str(child)) 172 sys.exit(2) 173 except pexpect.EOF: 174 print("EOF") 175 print(str(child)) 176 print(str(child.buffer)) 177 print(str(child.before)) 178 sys.exit(2) 179 180 return child 181 182# A random UTF-8 test with insert. 183# @param exe The executable. 184# @param args The arguments to pass to the executable. 185# @param env The environment. 186def test_utf8_0(exe, args, env, bc=True): 187 188 # Because both bc and dc use this, make sure the banner doesn't pop. 189 env["BC_BANNER"] = "0" 190 191 child = pexpect.spawn(exe, args=args, env=env, encoding='utf-8', codec_errors='ignore') 192 193 try: 194 195 # Just random UTF-8 I generated somewhow, plus ensuring that insert works. 196 write_str(child, "ﴪáá̵̗ã") 197 send(child, "\x1b[D\x1b[D\x1b[D\x1b\x1b[Aℐ") 198 send(child, "\n") 199 200 if bc: 201 send(child, "quit") 202 else: 203 send(child, "q") 204 205 send(child, "\n") 206 eat(child) 207 208 wait(child) 209 210 except pexpect.TIMEOUT: 211 traceback.print_tb(sys.exc_info()[2]) 212 print("timed out") 213 print(str(child)) 214 sys.exit(2) 215 except pexpect.EOF: 216 print("EOF") 217 print(str(child)) 218 print(str(child.buffer)) 219 print(str(child.before)) 220 sys.exit(2) 221 222 return child 223 224 225def test_utf8_1(exe, args, env, bc=True): 226 return test_utf8(exe, args, env, 0, bc) 227 228 229def test_utf8_2(exe, args, env, bc=True): 230 return test_utf8(exe, args, env, 1, bc) 231 232 233def test_utf8_3(exe, args, env, bc=True): 234 return test_utf8(exe, args, env, 2, bc) 235 236 237def test_utf8_4(exe, args, env, bc=True): 238 return test_utf8(exe, args, env, 3, bc) 239 240 241# This tests a SIGINT with reset followed by a SIGQUIT. 242# @param exe The executable. 243# @param args The arguments to pass to the executable. 244# @param env The environment. 245def test_sigint_sigquit(exe, args, env): 246 247 # Because both bc and dc use this, make sure the banner doesn't pop. 248 env["BC_BANNER"] = "0" 249 250 child = pexpect.spawn(exe, args=args, env=env) 251 252 try: 253 send(child, "\t") 254 expect(child, "\t") 255 send(child, "\x03") 256 # send(child, "\x1c") 257 wait(child) 258 except pexpect.TIMEOUT: 259 traceback.print_tb(sys.exc_info()[2]) 260 print("timed out") 261 print(str(child)) 262 sys.exit(2) 263 except pexpect.EOF: 264 print("EOF") 265 print(str(child)) 266 print(str(child.buffer)) 267 print(str(child.before)) 268 sys.exit(2) 269 270 return child 271 272 273# Test for EOF. 274# @param exe The executable. 275# @param args The arguments to pass to the executable. 276# @param env The environment. 277def test_eof(exe, args, env): 278 279 # Because both bc and dc use this, make sure the banner doesn't pop. 280 env["BC_BANNER"] = "0" 281 282 child = pexpect.spawn(exe, args=args, env=env) 283 284 try: 285 send(child, "123") 286 expect(child, "123") 287 send(child, "\x01") 288 send(child, "\x04") 289 send(child, "\x04") 290 send(child, "\x04") 291 wait(child) 292 except pexpect.TIMEOUT: 293 traceback.print_tb(sys.exc_info()[2]) 294 print("timed out") 295 print(str(child)) 296 sys.exit(2) 297 except pexpect.EOF: 298 print("EOF") 299 print(str(child)) 300 print(str(child.buffer)) 301 print(str(child.before)) 302 sys.exit(2) 303 304 return child 305 306 307# Test for quiting SIGINT. 308# @param exe The executable. 309# @param args The arguments to pass to the executable. 310# @param env The environment. 311def test_sigint(exe, args, env): 312 313 # Because both bc and dc use this, make sure the banner doesn't pop. 314 env["BC_BANNER"] = "0" 315 316 env["BC_SIGINT_RESET"] = "0" 317 env["DC_SIGINT_RESET"] = "0" 318 319 child = pexpect.spawn(exe, args=args, env=env) 320 321 try: 322 send(child, "\t") 323 expect(child, "\t") 324 send(child, "\x03") 325 wait(child) 326 except pexpect.TIMEOUT: 327 traceback.print_tb(sys.exc_info()[2]) 328 print("timed out") 329 print(str(child)) 330 sys.exit(2) 331 except pexpect.EOF: 332 print("EOF") 333 print(str(child)) 334 print(str(child.buffer)) 335 print(str(child.before)) 336 sys.exit(2) 337 338 return child 339 340 341# Test for SIGTSTP. 342# @param exe The executable. 343# @param args The arguments to pass to the executable. 344# @param env The environment. 345def test_sigtstp(exe, args, env): 346 347 # This test does not work on FreeBSD, so skip. 348 if sys.platform.startswith("freebsd"): 349 sys.exit(0) 350 351 # Because both bc and dc use this, make sure the banner doesn't pop. 352 env["BC_BANNER"] = "0" 353 354 child = pexpect.spawn(exe, args=args, env=env) 355 356 try: 357 send(child, "\t") 358 expect(child, "\t") 359 send(child, "\x13") 360 time.sleep(1) 361 if not child.isalive(): 362 print("child exited early") 363 print(str(child)) 364 print(str(child.buffer)) 365 sys.exit(1) 366 child.kill(signal.SIGCONT) 367 send(child, "quit") 368 send(child, "\n") 369 wait(child) 370 except pexpect.TIMEOUT: 371 traceback.print_tb(sys.exc_info()[2]) 372 print("timed out") 373 print(str(child)) 374 sys.exit(2) 375 except pexpect.EOF: 376 print("EOF") 377 print(str(child)) 378 print(str(child.buffer)) 379 print(str(child.before)) 380 sys.exit(2) 381 382 return child 383 384 385# Test for SIGSTOP. 386# @param exe The executable. 387# @param args The arguments to pass to the executable. 388# @param env The environment. 389def test_sigstop(exe, args, env): 390 391 # Because both bc and dc use this, make sure the banner doesn't pop. 392 env["BC_BANNER"] = "0" 393 394 child = pexpect.spawn(exe, args=args, env=env) 395 396 try: 397 send(child, "\t") 398 expect(child, "\t") 399 send(child, "\x14") 400 time.sleep(1) 401 if not child.isalive(): 402 print("child exited early") 403 print(str(child)) 404 print(str(child.buffer)) 405 sys.exit(1) 406 send(child, "\x13") 407 time.sleep(1) 408 if not child.isalive(): 409 print("child exited early") 410 print(str(child)) 411 print(str(child.buffer)) 412 sys.exit(1) 413 child.kill(signal.SIGCONT) 414 send(child, "quit") 415 send(child, "\n") 416 wait(child) 417 except pexpect.TIMEOUT: 418 traceback.print_tb(sys.exc_info()[2]) 419 print("timed out") 420 print(str(child)) 421 sys.exit(2) 422 except pexpect.EOF: 423 print("EOF") 424 print(str(child)) 425 print(str(child.buffer)) 426 print(str(child.before)) 427 sys.exit(2) 428 429 return child 430 431 432def test_bc_utf8_0(exe, args, env): 433 return test_utf8_0(exe, args, env, True) 434 435 436def test_bc_utf8_1(exe, args, env): 437 return test_utf8_1(exe, args, env, True) 438 439 440def test_bc_utf8_2(exe, args, env): 441 return test_utf8_2(exe, args, env, True) 442 443 444def test_bc_utf8_3(exe, args, env): 445 return test_utf8_3(exe, args, env, True) 446 447 448def test_bc_utf8_4(exe, args, env): 449 return test_utf8_4(exe, args, env, True) 450 451 452# Basic bc test. 453# @param exe The executable. 454# @param args The arguments to pass to the executable. 455# @param env The environment. 456def test_bc1(exe, args, env): 457 458 child = pexpect.spawn(exe, args=args, env=env) 459 460 try: 461 bc_banner(child) 462 write_str(child, "1") 463 check_line(child, "1") 464 write_str(child, "1") 465 check_line(child, "1") 466 send(child, "quit") 467 send(child, "\n") 468 wait(child) 469 except pexpect.TIMEOUT: 470 traceback.print_tb(sys.exc_info()[2]) 471 print("timed out") 472 print(str(child)) 473 sys.exit(2) 474 except pexpect.EOF: 475 print("EOF") 476 print(str(child)) 477 print(str(child.buffer)) 478 print(str(child.before)) 479 sys.exit(2) 480 481 return child 482 483 484# SIGINT with no history. 485# @param exe The executable. 486# @param args The arguments to pass to the executable. 487# @param env The environment. 488def test_bc2(exe, args, env): 489 490 env["TERM"] = "dumb" 491 492 child = pexpect.spawn(exe, args=args, env=env) 493 494 try: 495 bc_banner(child) 496 child.sendline("1") 497 check_line(child, "1", history=False) 498 time.sleep(1) 499 child.sendintr() 500 child.sendline("quit") 501 wait(child) 502 except pexpect.TIMEOUT: 503 traceback.print_tb(sys.exc_info()[2]) 504 print("timed out") 505 print(str(child)) 506 sys.exit(2) 507 except pexpect.EOF: 508 print("EOF") 509 print(str(child)) 510 print(str(child.buffer)) 511 print(str(child.before)) 512 sys.exit(2) 513 514 return child 515 516 517# Left and right arrows. 518# @param exe The executable. 519# @param args The arguments to pass to the executable. 520# @param env The environment. 521def test_bc3(exe, args, env): 522 523 child = pexpect.spawn(exe, args=args, env=env) 524 525 try: 526 bc_banner(child) 527 send(child, "\x1b[D\x1b[D\x1b[C\x1b[C") 528 send(child, "\n") 529 expect(child, prompt) 530 send(child, "12\x1b[D3\x1b[C4\x1bOD5\x1bOC6") 531 send(child, "\n") 532 check_line(child, "132546") 533 send(child, "12\x023\x064") 534 send(child, "\n") 535 check_line(child, "1324") 536 send(child, "12\x1b[H3\x1bOH\x01\x1b[H45\x1bOF6\x05\x1b[F7\x1bOH8") 537 send(child, "\n") 538 check_line(child, "84531267") 539 send(child, "quit") 540 send(child, "\n") 541 wait(child) 542 except pexpect.TIMEOUT: 543 traceback.print_tb(sys.exc_info()[2]) 544 print("timed out") 545 print(str(child)) 546 sys.exit(2) 547 except pexpect.EOF: 548 print("EOF") 549 print(str(child)) 550 print(str(child.buffer)) 551 print(str(child.before)) 552 sys.exit(2) 553 554 return child 555 556 557# Up and down arrows. 558# @param exe The executable. 559# @param args The arguments to pass to the executable. 560# @param env The environment. 561def test_bc4(exe, args, env): 562 563 child = pexpect.spawn(exe, args=args, env=env) 564 565 try: 566 bc_banner(child) 567 send(child, "\x1b[A\x1bOA\x1b[B\x1bOB") 568 send(child, "\n") 569 expect(child, prompt) 570 write_str(child, "15") 571 check_line(child, "15") 572 write_str(child, "2^16") 573 check_line(child, "65536") 574 send(child, "\x1b[A\x1bOA") 575 send(child, "\n") 576 check_line(child, "15") 577 send(child, "\x1b[A\x1bOA\x1b[A\x1b[B") 578 check_line(child, "65536") 579 send(child, "\x1b[A\x1bOA\x0e\x1b[A\x1b[A\x1b[A\x1b[B\x10\x1b[B\x1b[B\x1bOB\x1b[B\x1bOA") 580 send(child, "\n") 581 check_line(child, "65536") 582 send(child, "quit") 583 send(child, "\n") 584 wait(child) 585 except pexpect.TIMEOUT: 586 traceback.print_tb(sys.exc_info()[2]) 587 print("timed out") 588 print(str(child)) 589 sys.exit(2) 590 except pexpect.EOF: 591 print("EOF") 592 print(str(child)) 593 print(str(child.buffer)) 594 print(str(child.before)) 595 sys.exit(2) 596 597 return child 598 599 600# Clear screen. 601# @param exe The executable. 602# @param args The arguments to pass to the executable. 603# @param env The environment. 604def test_bc5(exe, args, env): 605 606 child = pexpect.spawn(exe, args=args, env=env) 607 608 try: 609 bc_banner(child) 610 send(child, "\x0c") 611 send(child, "quit") 612 send(child, "\n") 613 wait(child) 614 except pexpect.TIMEOUT: 615 traceback.print_tb(sys.exc_info()[2]) 616 print("timed out") 617 print(str(child)) 618 sys.exit(2) 619 except pexpect.EOF: 620 print("EOF") 621 print(str(child)) 622 print(str(child.buffer)) 623 print(str(child.before)) 624 sys.exit(2) 625 626 return child 627 628 629# Printed material without a newline. 630# @param exe The executable. 631# @param args The arguments to pass to the executable. 632# @param env The environment. 633def test_bc6(exe, args, env): 634 635 child = pexpect.spawn(exe, args=args, env=env) 636 637 try: 638 bc_banner(child) 639 send(child, "print \"Enter number: \"") 640 send(child, "\n") 641 expect(child, "Enter number: ") 642 send(child, "4\x1b[A\x1b[A") 643 send(child, "\n") 644 send(child, "quit") 645 send(child, "\n") 646 wait(child) 647 except pexpect.TIMEOUT: 648 traceback.print_tb(sys.exc_info()[2]) 649 print("timed out") 650 print(str(child)) 651 sys.exit(2) 652 except pexpect.EOF: 653 print("EOF") 654 print(str(child)) 655 print(str(child.buffer)) 656 print(str(child.before)) 657 sys.exit(2) 658 659 return child 660 661 662# Word start and word end. 663# @param exe The executable. 664# @param args The arguments to pass to the executable. 665# @param env The environment. 666def test_bc7(exe, args, env): 667 668 child = pexpect.spawn(exe, args=args, env=env) 669 670 try: 671 bc_banner(child) 672 send(child, "\x1bb\x1bb\x1bf\x1bf") 673 send(child, "\n") 674 expect(child, prompt) 675 send(child, "\x1b[0~\x1b[3a") 676 send(child, "\n") 677 expect(child, prompt) 678 send(child, "\x1b[0;4\x1b[0A") 679 send(child, "\n") 680 expect(child, prompt) 681 send(child, "\t") 682 send(child, "\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb") 683 send(child, "\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf") 684 send(child, "\n") 685 expect(child, prompt) 686 write_str(child, "12 + 34 + 56 + 78 + 90") 687 check_line(child, "270") 688 send(child, "\x1b[A") 689 send(child, "\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb") 690 send(child, "\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf") 691 check_line(child, "270") 692 send(child, "\x1b[A") 693 send(child, "\x1bh\x1bh\x1bf + 14 ") 694 send(child, "\n") 695 check_line(child, "284") 696 send(child, "quit") 697 send(child, "\n") 698 wait(child) 699 except pexpect.TIMEOUT: 700 traceback.print_tb(sys.exc_info()[2]) 701 print("timed out") 702 print(str(child)) 703 sys.exit(2) 704 except pexpect.EOF: 705 print("EOF") 706 print(str(child)) 707 print(str(child.buffer)) 708 print(str(child.before)) 709 sys.exit(2) 710 711 return child 712 713 714# Backspace. 715# @param exe The executable. 716# @param args The arguments to pass to the executable. 717# @param env The environment. 718def test_bc8(exe, args, env): 719 720 child = pexpect.spawn(exe, args=args, env=env) 721 722 try: 723 bc_banner(child) 724 send(child, "12\x1b[D3\x1b[C4\x08\x7f") 725 send(child, "\n") 726 check_line(child, "13") 727 send(child, "quit") 728 send(child, "\n") 729 wait(child) 730 except pexpect.TIMEOUT: 731 traceback.print_tb(sys.exc_info()[2]) 732 print("timed out") 733 print(str(child)) 734 sys.exit(2) 735 except pexpect.EOF: 736 print("EOF") 737 print(str(child)) 738 print(str(child.buffer)) 739 print(str(child.before)) 740 sys.exit(2) 741 742 return child 743 744 745# Backspace and delete words. 746# @param exe The executable. 747# @param args The arguments to pass to the executable. 748# @param env The environment. 749def test_bc9(exe, args, env): 750 751 child = pexpect.spawn(exe, args=args, env=env) 752 753 try: 754 bc_banner(child) 755 send(child, "\x1b[0;5D\x1b[0;5D\x1b[0;5D\x1b[0;5C\x1b[0;5D\x1bd\x1b[3~\x1b[d\x1b[d\x1b[d\x1b[d\x7f\x7f\x7f") 756 send(child, "\n") 757 expect(child, prompt) 758 write_str(child, "12 + 34 + 56 + 78 + 90") 759 check_line(child, "270") 760 send(child, "\x1b[A") 761 send(child, "\x1b[0;5D\x1b[0;5D\x1b[0;5D\x1b[0;5C\x1b[0;5D\x1bd\x1b[3~\x1b[d\x1b[d\x1b[d\x1b[d\x7f\x7f\x7f") 762 send(child, "\n") 763 check_line(child, "102") 764 send(child, "\x1b[A") 765 send(child, "\x17\x17") 766 send(child, "\n") 767 check_line(child, "46") 768 send(child, "\x17\x17") 769 send(child, "\n") 770 expect(child, prompt) 771 send(child, "quit") 772 send(child, "\n") 773 wait(child) 774 except pexpect.TIMEOUT: 775 traceback.print_tb(sys.exc_info()[2]) 776 print("timed out") 777 print(str(child)) 778 sys.exit(2) 779 except pexpect.EOF: 780 print("EOF") 781 print(str(child)) 782 print(str(child.buffer)) 783 print(str(child.before)) 784 sys.exit(2) 785 786 return child 787 788 789# Backspace and delete words 2. 790# @param exe The executable. 791# @param args The arguments to pass to the executable. 792# @param env The environment. 793def test_bc10(exe, args, env): 794 795 child = pexpect.spawn(exe, args=args, env=env) 796 797 try: 798 bc_banner(child) 799 send(child, "\x1b[3~\x1b[3~") 800 send(child, "\n") 801 expect(child, prompt) 802 send(child, " \x1b[3~\x1b[3~") 803 send(child, "\n") 804 expect(child, prompt) 805 write_str(child, "12 + 34 + 56 + 78 + 90") 806 check_line(child, "270") 807 send(child, "\x1b[A\x1b[A\x1b[A\x1b[B\x1b[B\x1b[B\x1b[A") 808 send(child, "\n") 809 check_line(child, "270") 810 send(child, "\x1b[A\x1b[0;5D\x1b[0;5D\x0b") 811 send(child, "\n") 812 check_line(child, "180") 813 send(child, "\x1b[A\x1521") 814 check_line(child, "21") 815 send(child, "quit") 816 send(child, "\n") 817 wait(child) 818 except pexpect.TIMEOUT: 819 traceback.print_tb(sys.exc_info()[2]) 820 print("timed out") 821 print(str(child)) 822 sys.exit(2) 823 except pexpect.EOF: 824 print("EOF") 825 print(str(child)) 826 print(str(child.buffer)) 827 print(str(child.before)) 828 sys.exit(2) 829 830 return child 831 832 833# Swap. 834# @param exe The executable. 835# @param args The arguments to pass to the executable. 836# @param env The environment. 837def test_bc11(exe, args, env): 838 839 child = pexpect.spawn(exe, args=args, env=env) 840 841 try: 842 bc_banner(child) 843 send(child, "\x1b[A\x02\x14") 844 send(child, "\n") 845 expect(child, prompt) 846 write_str(child, "12 + 34 + 56 + 78") 847 check_line(child, "180") 848 send(child, "\x1b[A\x02\x14") 849 check_line(child, "189") 850 send(child, "quit") 851 send(child, "\n") 852 wait(child) 853 except pexpect.TIMEOUT: 854 traceback.print_tb(sys.exc_info()[2]) 855 print("timed out") 856 print(str(child)) 857 sys.exit(2) 858 except pexpect.EOF: 859 print("EOF") 860 print(str(child)) 861 print(str(child.buffer)) 862 print(str(child.before)) 863 sys.exit(2) 864 865 return child 866 867 868# Non-fatal error. 869# @param exe The executable. 870# @param args The arguments to pass to the executable. 871# @param env The environment. 872def test_bc12(exe, args, env): 873 874 child = pexpect.spawn(exe, args=args, env=env) 875 876 try: 877 bc_banner(child) 878 send(child, "12 +") 879 send(child, "\n") 880 time.sleep(1) 881 if not child.isalive(): 882 print("child exited early") 883 print(str(child)) 884 print(str(child.buffer)) 885 sys.exit(1) 886 send(child, "quit") 887 send(child, "\n") 888 wait(child) 889 except pexpect.TIMEOUT: 890 traceback.print_tb(sys.exc_info()[2]) 891 print("timed out") 892 print(str(child)) 893 sys.exit(2) 894 except pexpect.EOF: 895 print("EOF") 896 print(str(child)) 897 print(str(child.buffer)) 898 print(str(child.before)) 899 sys.exit(2) 900 901 return child 902 903 904def test_dc_utf8_0(exe, args, env): 905 return test_utf8_0(exe, args, env, False) 906 907 908def test_dc_utf8_1(exe, args, env): 909 return test_utf8_1(exe, args, env, False) 910 911 912def test_dc_utf8_2(exe, args, env): 913 return test_utf8_2(exe, args, env, False) 914 915 916def test_dc_utf8_3(exe, args, env): 917 return test_utf8_3(exe, args, env, False) 918 919 920def test_dc_utf8_4(exe, args, env): 921 return test_utf8_4(exe, args, env, False) 922 923 924# Basic dc test. 925# @param exe The executable. 926# @param args The arguments to pass to the executable. 927# @param env The environment. 928def test_dc1(exe, args, env): 929 930 child = pexpect.spawn(exe, args=args, env=env) 931 932 try: 933 write_str(child, "1pR") 934 check_line(child, "1") 935 write_str(child, "1pR") 936 check_line(child, "1") 937 write_str(child, "q") 938 send(child, "\n") 939 wait(child) 940 except pexpect.TIMEOUT: 941 traceback.print_tb(sys.exc_info()[2]) 942 print("timed out") 943 print(str(child)) 944 sys.exit(2) 945 except pexpect.EOF: 946 print("EOF") 947 print(str(child)) 948 print(str(child.buffer)) 949 print(str(child.before)) 950 sys.exit(2) 951 952 return child 953 954 955# SIGINT with quit. 956# @param exe The executable. 957# @param args The arguments to pass to the executable. 958# @param env The environment. 959def test_dc2(exe, args, env): 960 961 env["TERM"] = "dumb" 962 963 child = pexpect.spawn(exe, args=args, env=env) 964 965 try: 966 child.sendline("1pR") 967 check_line(child, "1", history=False) 968 time.sleep(1) 969 child.sendintr() 970 child.sendline("q") 971 wait(child) 972 except pexpect.TIMEOUT: 973 traceback.print_tb(sys.exc_info()[2]) 974 print("timed out") 975 print(str(child)) 976 sys.exit(2) 977 except pexpect.EOF: 978 print("EOF") 979 print(str(child)) 980 print(str(child.buffer)) 981 print(str(child.before)) 982 sys.exit(2) 983 984 return child 985 986 987# Execute string. 988# @param exe The executable. 989# @param args The arguments to pass to the executable. 990# @param env The environment. 991def test_dc3(exe, args, env): 992 993 child = pexpect.spawn(exe, args=args, env=env) 994 995 try: 996 write_str(child, "[1 15+pR]x") 997 check_line(child, "16") 998 write_str(child, "1pR") 999 check_line(child, "1") 1000 write_str(child, "q") 1001 send(child, "\n") 1002 wait(child) 1003 except pexpect.TIMEOUT: 1004 traceback.print_tb(sys.exc_info()[2]) 1005 print("timed out") 1006 print(str(child)) 1007 sys.exit(2) 1008 except pexpect.EOF: 1009 print("EOF") 1010 print(str(child)) 1011 print(str(child.buffer)) 1012 print(str(child.before)) 1013 sys.exit(2) 1014 1015 return child 1016 1017 1018# The array of bc tests. 1019bc_tests = [ 1020 test_bc_utf8_0, 1021 test_bc_utf8_1, 1022 test_bc_utf8_2, 1023 test_bc_utf8_3, 1024 test_bc_utf8_4, 1025 test_sigint_sigquit, 1026 test_eof, 1027 test_sigint, 1028 test_sigtstp, 1029 test_sigstop, 1030 test_bc1, 1031 test_bc2, 1032 test_bc3, 1033 test_bc4, 1034 test_bc5, 1035 test_bc6, 1036 test_bc7, 1037 test_bc8, 1038 test_bc9, 1039 test_bc10, 1040 test_bc11, 1041 test_bc12, 1042] 1043 1044# The array of dc tests. 1045dc_tests = [ 1046 test_dc_utf8_0, 1047 test_dc_utf8_1, 1048 test_dc_utf8_2, 1049 test_dc_utf8_3, 1050 test_dc_utf8_4, 1051 test_sigint_sigquit, 1052 test_eof, 1053 test_sigint, 1054 test_dc1, 1055 test_dc2, 1056 test_dc3, 1057] 1058 1059 1060# Print the usage and exit with an error. 1061def usage(): 1062 print("usage: {} [-t] dir [-a] test_idx [exe options...]".format(script)) 1063 print(" The valid values for dir are: 'bc' and 'dc'.") 1064 print(" The max test_idx for bc is {}.".format(len(bc_tests) - 1)) 1065 print(" The max test_idx for dc is {}.".format(len(dc_tests) - 1)) 1066 print(" If -a is given, the number of tests for dir is printed.") 1067 print(" No tests are run.") 1068 sys.exit(1) 1069 1070 1071# Must run this script alone. 1072if __name__ != "__main__": 1073 usage() 1074 1075if len(sys.argv) < 2: 1076 usage() 1077 1078idx = 1 1079 1080exedir = sys.argv[idx] 1081 1082idx += 1 1083 1084if exedir == "-t": 1085 do_test = True 1086 exedir = sys.argv[idx] 1087 idx += 1 1088else: 1089 do_test = False 1090 1091test_idx = sys.argv[idx] 1092 1093idx += 1 1094 1095if test_idx == "-a": 1096 if exedir == "bc": 1097 l = len(bc_tests) 1098 else: 1099 l = len(dc_tests) 1100 print("{}".format(l)) 1101 sys.exit(0) 1102 1103test_idx = int(test_idx) 1104 1105# Set a default executable unless we have one. 1106if len(sys.argv) >= idx + 1: 1107 exe = sys.argv[idx] 1108else: 1109 exe = testdir + "/../bin/" + exedir 1110 1111exebase = os.path.basename(exe) 1112 1113# Use the correct options. 1114if exebase == "bc": 1115 halt = "halt\n" 1116 options = "-l" 1117 test_array = bc_tests 1118else: 1119 halt = "q\n" 1120 options = "-x" 1121 test_array = dc_tests 1122 1123# More command-line processing. 1124if len(sys.argv) > idx + 1: 1125 exe = [ exe, sys.argv[idx + 1:], options ] 1126else: 1127 exe = [ exe, options ] 1128 1129# This is the environment necessary for most tests. 1130env = { 1131 "BC_BANNER": "1", 1132 "BC_PROMPT": "1", 1133 "DC_PROMPT": "1", 1134 "BC_TTY_MODE": "1", 1135 "DC_TTY_MODE": "1", 1136 "BC_SIGINT_RESET": "1", 1137 "DC_SIGINT_RESET": "1", 1138} 1139 1140# Make sure to include the outside environment. 1141env.update(os.environ) 1142env.pop("BC_ENV_ARGS", None) 1143env.pop("BC_LINE_LENGTH", None) 1144env.pop("DC_ENV_ARGS", None) 1145env.pop("DC_LINE_LENGTH", None) 1146 1147# Run the correct test. 1148child = test_array[test_idx](exe[0], exe[1:], env) 1149 1150child.close() 1151 1152exit = child.exitstatus 1153 1154if exit is not None and exit != 0: 1155 print("child failed; expected exit code 0, got {}".format(exit)) 1156 print(str(child)) 1157 sys.exit(1) 1158