| #! /usr/bin/python |
| # |
| # SPDX-License-Identifier: BSD-2-Clause |
| # |
| # Copyright (c) 2018-2021 Gavin D. Howard and contributors. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # |
| # * Redistributions of source code must retain the above copyright notice, this |
| # list of conditions and the following disclaimer. |
| # |
| # * Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation |
| # and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| # POSSIBILITY OF SUCH DAMAGE. |
| # |
| |
| import os, sys |
| import time |
| import signal |
| |
| try: |
| import pexpect |
| except ImportError: |
| print("Could not find pexpect. Skipping...") |
| sys.exit(0) |
| |
| # Housekeeping. |
| script = sys.argv[0] |
| testdir = os.path.dirname(script) |
| |
| if "BC_TEST_OUTPUT_DIR" in os.environ: |
| outputdir = os.environ["BC_TEST_OUTPUT_DIR"] |
| else: |
| outputdir = testdir |
| |
| prompt = ">>> " |
| |
| # This array is for escaping characters that are necessary to escape when |
| # outputting to pexpect. Since pexpect takes regexes, these characters confuse |
| # it unless we escape them. |
| escapes = [ |
| ']', |
| '[', |
| '+', |
| ] |
| |
| # UTF-8 stress tests. |
| utf8_stress1 = "ᆬḰ䋔䗅㜲ತ咡䒢岤䳰稨⣡嶣㷡嶏ⵐ䄺嵕ਅ奰痚㆜䊛拂䅙૩➋䛿ቬ竳Ϳᅠ❄产翷䮊௷Ỉ䷒䳜㛠➕傎ᗋᏯਕ䆐悙癐㺨" |
| utf8_stress2 = "韠싧돳넨큚ꉿ뮴픷ꉲ긌�최릙걆鳬낽ꪁ퍼鈴핐黙헶ꪈ뮩쭀锻끥鉗겉욞며뛯�ﻼ�度錐�" |
| utf8_stress3 = "곻�䣹昲蜴Ὓ桢㎏⚦珢畣갴ﭱ鶶ๅ뀁彻ꖒ䔾ꢚﱤ햔햞㐹�鼳뵡▿ⶾ꠩�纞⊐佧�ⵟ霘紳㱔籠뎼⊓搧硤" |
| utf8_stress4 = "ᄀ𖢾🏴��" |
| |
| # An easy array for UTF-8 tests. |
| utf8_stress_strs = [ |
| utf8_stress1, |
| utf8_stress2, |
| utf8_stress3, |
| utf8_stress4, |
| ] |
| |
| |
| # Eats all of the child's data. |
| # @param child The child whose data should be eaten. |
| def eat(child): |
| while child.before is not None and len(child.before) > 0: |
| child.expect(".*") |
| |
| |
| # Send data to a child. This makes sure the buffers are empty first. |
| # @param child The child to send data to. |
| # @param data The data to send. |
| def send(child, data): |
| eat(child) |
| child.send(data) |
| |
| |
| def wait(child): |
| if child.isalive(): |
| child.sendeof() |
| time.sleep(1) |
| if child.isalive(): |
| child.kill(signal.SIGTERM) |
| time.sleep(1) |
| if child.isalive(): |
| child.kill(signal.SIGKILL) |
| child.wait() |
| |
| |
| # Check that the child output the expected line. If history is false, then |
| # the output should change. |
| def check_line(child, expected, prompt=">>> ", history=True): |
| send(child, "\n") |
| prefix = "\r\n" if history else "" |
| child.expect(prefix + expected + "\r\n" + prompt) |
| |
| |
| # Write a string to output, checking all of the characters are output, |
| # one-by-one. |
| def write_str(child, s): |
| for c in s: |
| send(child, c) |
| if c in escapes: |
| child.expect("\\{}".format(c)) |
| else: |
| child.expect(c) |
| |
| |
| # Check the bc banner. |
| # @param child The child process. |
| def bc_banner(child): |
| bc_banner1 = "bc [0-9]+\.[0-9]+\.[0-9]+\r\n" |
| bc_banner2 = "Copyright \(c\) 2018-[2-9][0-9][0-9][0-9] Gavin D. Howard and contributors\r\n" |
| bc_banner3 = "Report bugs at: https://git.yzena.com/gavin/bc\r\n\r\n" |
| bc_banner4 = "This is free software with ABSOLUTELY NO WARRANTY.\r\n\r\n" |
| child.expect(bc_banner1) |
| child.expect(bc_banner2) |
| child.expect(bc_banner3) |
| child.expect(bc_banner4) |
| child.expect(prompt) |
| |
| |
| # Common UTF-8 testing function. The index is the index into utf8_stress_strs |
| # for which stress string to use. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| # @param idx The index of the UTF-8 stress string. |
| def test_utf8(exe, args, env, idx, bc=True): |
| |
| # Because both bc and dc use this, make sure the banner doesn't pop. |
| env["BC_BANNER"] = "0" |
| |
| child = pexpect.spawn(exe, args=args, env=env, encoding='utf-8', codec_errors='ignore') |
| |
| try: |
| |
| # Write the stress string. |
| send(child, utf8_stress_strs[idx]) |
| send(child, "\n") |
| |
| if bc: |
| send(child, "quit") |
| else: |
| send(child, "q") |
| |
| send(child, "\n") |
| |
| wait(child) |
| |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| # A random UTF-8 test with insert. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_utf8_0(exe, args, env, bc=True): |
| |
| # Because both bc and dc use this, make sure the banner doesn't pop. |
| env["BC_BANNER"] = "0" |
| |
| child = pexpect.spawn(exe, args=args, env=env, encoding='utf-8', codec_errors='ignore') |
| |
| try: |
| |
| # Just random UTF-8 I generated somewhow, plus ensuring that insert works. |
| write_str(child, "ﴪáá̵̗🈐ã") |
| send(child, "\x1b[D\x1b[D\x1b[D\x1b\x1b[Aℐ") |
| send(child, "\n") |
| |
| if bc: |
| send(child, "quit") |
| else: |
| send(child, "q") |
| |
| send(child, "\n") |
| eat(child) |
| |
| wait(child) |
| |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| def test_utf8_1(exe, args, env, bc=True): |
| return test_utf8(exe, args, env, 0, bc) |
| |
| |
| def test_utf8_2(exe, args, env, bc=True): |
| return test_utf8(exe, args, env, 1, bc) |
| |
| |
| def test_utf8_3(exe, args, env, bc=True): |
| return test_utf8(exe, args, env, 2, bc) |
| |
| |
| def test_utf8_4(exe, args, env, bc=True): |
| return test_utf8(exe, args, env, 3, bc) |
| |
| |
| # This tests a SIGINT with reset followed by a SIGQUIT. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_sigint_sigquit(exe, args, env): |
| |
| # Because both bc and dc use this, make sure the banner doesn't pop. |
| env["BC_BANNER"] = "0" |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| send(child, "\t") |
| child.expect(" ") |
| send(child, "\x03") |
| send(child, "\x1c") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Test for EOF. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_eof(exe, args, env): |
| |
| # Because both bc and dc use this, make sure the banner doesn't pop. |
| env["BC_BANNER"] = "0" |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| send(child, "\t") |
| child.expect(" ") |
| send(child, "\x04") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Test for quiting SIGINT. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_sigint(exe, args, env): |
| |
| # Because both bc and dc use this, make sure the banner doesn't pop. |
| env["BC_BANNER"] = "0" |
| |
| env["BC_SIGINT_RESET"] = "0" |
| env["DC_SIGINT_RESET"] = "0" |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| send(child, "\t") |
| child.expect(" ") |
| send(child, "\x03") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Test for SIGTSTP. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_sigtstp(exe, args, env): |
| |
| # Because both bc and dc use this, make sure the banner doesn't pop. |
| env["BC_BANNER"] = "0" |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| send(child, "\t") |
| child.expect(" ") |
| send(child, "\x13") |
| time.sleep(1) |
| if not child.isalive(): |
| print("child exited early") |
| print(str(child)) |
| print(str(child.buffer)) |
| sys.exit(1) |
| child.kill(signal.SIGCONT) |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Test for SIGSTOP. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_sigstop(exe, args, env): |
| |
| # Because both bc and dc use this, make sure the banner doesn't pop. |
| env["BC_BANNER"] = "0" |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| send(child, "\t") |
| child.expect(" ") |
| send(child, "\x14") |
| time.sleep(1) |
| if not child.isalive(): |
| print("child exited early") |
| print(str(child)) |
| print(str(child.buffer)) |
| sys.exit(1) |
| send(child, "\x13") |
| time.sleep(1) |
| if not child.isalive(): |
| print("child exited early") |
| print(str(child)) |
| print(str(child.buffer)) |
| sys.exit(1) |
| child.kill(signal.SIGCONT) |
| send(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| def test_bc_utf8_0(exe, args, env): |
| return test_utf8_0(exe, args, env, True) |
| |
| |
| def test_bc_utf8_1(exe, args, env): |
| return test_utf8_1(exe, args, env, True) |
| |
| |
| def test_bc_utf8_2(exe, args, env): |
| return test_utf8_2(exe, args, env, True) |
| |
| |
| def test_bc_utf8_3(exe, args, env): |
| return test_utf8_3(exe, args, env, True) |
| |
| |
| def test_bc_utf8_4(exe, args, env): |
| return test_utf8_4(exe, args, env, True) |
| |
| |
| # Basic bc test. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc1(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| write_str(child, "1") |
| check_line(child, "1") |
| write_str(child, "1") |
| check_line(child, "1") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # SIGINT with no history. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc2(exe, args, env): |
| |
| env["TERM"] = "dumb" |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| child.sendline("1") |
| check_line(child, "1", history=False) |
| time.sleep(1) |
| child.sendintr() |
| child.sendline("quit") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Left and right arrows. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc3(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "\x1b[D\x1b[D\x1b[C\x1b[C") |
| send(child, "\n") |
| child.expect(prompt) |
| send(child, "12\x1b[D3\x1b[C4\x1bOD5\x1bOC6") |
| send(child, "\n") |
| check_line(child, "132546") |
| send(child, "12\x023\x064") |
| send(child, "\n") |
| check_line(child, "1324") |
| send(child, "12\x1b[H3\x1bOH\x01\x1b[H45\x1bOF6\x05\x1b[F7\x1bOH8") |
| send(child, "\n") |
| check_line(child, "84531267") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Up and down arrows. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc4(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "\x1b[A\x1bOA\x1b[B\x1bOB") |
| send(child, "\n") |
| child.expect(prompt) |
| write_str(child, "15") |
| check_line(child, "15") |
| write_str(child, "2^16") |
| check_line(child, "65536") |
| send(child, "\x1b[A\x1bOA") |
| send(child, "\n") |
| check_line(child, "15") |
| send(child, "\x1b[A\x1bOA\x1b[A\x1b[B") |
| check_line(child, "65536") |
| send(child, "\x1b[A\x1bOA\x0e\x1b[A\x1b[A\x1b[A\x1b[B\x10\x1b[B\x1b[B\x1bOB\x1b[B\x1bOA") |
| send(child, "\n") |
| check_line(child, "65536") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Clear screen. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc5(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "\x0c") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Printed material without a newline. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc6(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "print \"Enter number: \"") |
| send(child, "\n") |
| child.expect("Enter number: ") |
| send(child, "4\x1b[A\x1b[A") |
| send(child, "\n") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Word start and word end. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc7(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "\x1bb\x1bb\x1bf\x1bf") |
| send(child, "\n") |
| child.expect(prompt) |
| send(child, "\x1b[0~\x1b[3a") |
| send(child, "\n") |
| child.expect(prompt) |
| send(child, "\x1b[0;4\x1b[0A") |
| send(child, "\n") |
| child.expect(prompt) |
| send(child, " ") |
| send(child, "\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb") |
| send(child, "\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf") |
| send(child, "\n") |
| child.expect(prompt) |
| write_str(child, "12 + 34 + 56 + 78 + 90") |
| check_line(child, "270") |
| send(child, "\x1b[A") |
| send(child, "\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb\x1bb") |
| send(child, "\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf\x1bf") |
| check_line(child, "270") |
| send(child, "\x1b[A") |
| send(child, "\x1bh\x1bh\x1bf + 14 ") |
| send(child, "\n") |
| check_line(child, "284") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Backspace. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc8(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "12\x1b[D3\x1b[C4\x08\x7f") |
| send(child, "\n") |
| check_line(child, "13") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Backspace and delete words. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc9(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| 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") |
| send(child, "\n") |
| child.expect(prompt) |
| write_str(child, "12 + 34 + 56 + 78 + 90") |
| check_line(child, "270") |
| send(child, "\x1b[A") |
| 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") |
| send(child, "\n") |
| check_line(child, "102") |
| send(child, "\x1b[A") |
| send(child, "\x17\x17") |
| send(child, "\n") |
| check_line(child, "46") |
| send(child, "\x17\x17") |
| send(child, "\n") |
| child.expect(prompt) |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Backspace and delete words 2. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc10(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "\x1b[3~\x1b[3~") |
| send(child, "\n") |
| child.expect(prompt) |
| send(child, " \x1b[3~\x1b[3~") |
| send(child, "\n") |
| child.expect(prompt) |
| write_str(child, "12 + 34 + 56 + 78 + 90") |
| check_line(child, "270") |
| send(child, "\x1b[A\x1b[A\x1b[A\x1b[B\x1b[B\x1b[B\x1b[A") |
| send(child, "\n") |
| check_line(child, "270") |
| send(child, "\x1b[A\x1b[0;5D\x1b[0;5D\x0b") |
| send(child, "\n") |
| check_line(child, "180") |
| send(child, "\x1b[A\x1521") |
| check_line(child, "21") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Swap. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc11(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "\x1b[A\x02\x14") |
| send(child, "\n") |
| child.expect(prompt) |
| write_str(child, "12 + 34 + 56 + 78") |
| check_line(child, "180") |
| send(child, "\x1b[A\x02\x14") |
| check_line(child, "189") |
| write_str(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Non-fatal error. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_bc12(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| bc_banner(child) |
| send(child, "12 +") |
| send(child, "\n") |
| time.sleep(1) |
| if not child.isalive(): |
| print("child exited early") |
| print(str(child)) |
| print(str(child.buffer)) |
| sys.exit(1) |
| send(child, "quit") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| def test_dc_utf8_0(exe, args, env): |
| return test_utf8_0(exe, args, env, False) |
| |
| |
| def test_dc_utf8_1(exe, args, env): |
| return test_utf8_1(exe, args, env, False) |
| |
| |
| def test_dc_utf8_2(exe, args, env): |
| return test_utf8_2(exe, args, env, False) |
| |
| |
| def test_dc_utf8_3(exe, args, env): |
| return test_utf8_3(exe, args, env, False) |
| |
| |
| def test_dc_utf8_4(exe, args, env): |
| return test_utf8_4(exe, args, env, False) |
| |
| |
| # Basic dc test. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_dc1(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| write_str(child, "1pR") |
| check_line(child, "1") |
| write_str(child, "1pR") |
| check_line(child, "1") |
| write_str(child, "q") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # SIGINT with quit. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_dc2(exe, args, env): |
| |
| env["TERM"] = "dumb" |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| child.sendline("1pR") |
| check_line(child, "1", history=False) |
| time.sleep(1) |
| child.sendintr() |
| child.sendline("q") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # Execute string. |
| # @param exe The executable. |
| # @param args The arguments to pass to the executable. |
| # @param env The environment. |
| def test_dc3(exe, args, env): |
| |
| child = pexpect.spawn(exe, args=args, env=env) |
| |
| try: |
| write_str(child, "[1 15+pR]x") |
| check_line(child, "16") |
| write_str(child, "1pR") |
| check_line(child, "1") |
| write_str(child, "q") |
| send(child, "\n") |
| wait(child) |
| except pexpect.TIMEOUT: |
| print("timed out") |
| print(str(child)) |
| sys.exit(2) |
| except pexpect.EOF: |
| print("EOF") |
| print(str(child)) |
| print(str(child.buffer)) |
| print(str(child.before)) |
| sys.exit(2) |
| |
| return child |
| |
| |
| # The array of bc tests. |
| bc_tests = [ |
| test_bc_utf8_0, |
| test_bc_utf8_1, |
| test_bc_utf8_2, |
| test_bc_utf8_3, |
| test_bc_utf8_4, |
| test_sigint_sigquit, |
| test_eof, |
| test_sigint, |
| test_sigtstp, |
| test_sigstop, |
| test_bc1, |
| test_bc2, |
| test_bc3, |
| test_bc4, |
| test_bc5, |
| test_bc6, |
| test_bc7, |
| test_bc8, |
| test_bc9, |
| test_bc10, |
| test_bc11, |
| test_bc12, |
| ] |
| |
| # The array of dc tests. |
| dc_tests = [ |
| test_dc_utf8_0, |
| test_dc_utf8_1, |
| test_dc_utf8_2, |
| test_dc_utf8_3, |
| test_sigint_sigquit, |
| test_eof, |
| test_sigint, |
| test_dc1, |
| test_dc2, |
| test_dc3, |
| ] |
| |
| |
| # Print the usage and exit with an error. |
| def usage(): |
| print("usage: {} [-t] dir [-a] test_idx [exe options...]".format(script)) |
| print(" The valid values for dir are: 'bc' and 'dc'.") |
| print(" The max test_idx for bc is {}.".format(len(bc_tests) - 1)) |
| print(" The max test_idx for dc is {}.".format(len(dc_tests) - 1)) |
| print(" If -a is given, the number of tests for dir is printed.") |
| print(" No tests are run.") |
| sys.exit(1) |
| |
| |
| # Must run this script alone. |
| if __name__ != "__main__": |
| usage() |
| |
| if len(sys.argv) < 2: |
| usage() |
| |
| idx = 1 |
| |
| exedir = sys.argv[idx] |
| |
| idx += 1 |
| |
| if exedir == "-t": |
| do_test = True |
| exedir = sys.argv[idx] |
| idx += 1 |
| else: |
| do_test = False |
| |
| test_idx = sys.argv[idx] |
| |
| idx += 1 |
| |
| if test_idx == "-a": |
| if exedir == "bc": |
| l = len(bc_tests) |
| else: |
| l = len(dc_tests) |
| print("{}".format(l)) |
| sys.exit(0) |
| |
| test_idx = int(test_idx) |
| |
| # Set a default executable unless we have one. |
| if len(sys.argv) >= idx + 1: |
| exe = sys.argv[idx] |
| else: |
| exe = testdir + "/../bin/" + exedir |
| |
| exebase = os.path.basename(exe) |
| |
| # Use the correct options. |
| if exebase == "bc": |
| halt = "halt\n" |
| options = "-lq" |
| test_array = bc_tests |
| else: |
| halt = "q\n" |
| options = "-x" |
| test_array = dc_tests |
| |
| # More command-line processing. |
| if len(sys.argv) > idx + 1: |
| exe = [ exe, sys.argv[idx + 1:], options ] |
| else: |
| exe = [ exe, options ] |
| |
| # This is the environment necessary for most tests. |
| env = { |
| "BC_BANNER": "1", |
| "BC_PROMPT": "1", |
| "DC_PROMPT": "1", |
| "BC_TTY_MODE": "1", |
| "DC_TTY_MODE": "1", |
| "BC_SIGINT_RESET": "1", |
| "DC_SIGINT_RESET": "1", |
| } |
| |
| # Make sure to include the outside environment. |
| env.update(os.environ) |
| env.pop("BC_ENV_ARGS", None) |
| env.pop("BC_LINE_LENGTH", None) |
| env.pop("DC_ENV_ARGS", None) |
| env.pop("DC_LINE_LENGTH", None) |
| |
| # Run the correct test. |
| child = test_array[test_idx](exe[0], exe[1:], env) |
| |
| child.close() |
| |
| exit = child.exitstatus |
| |
| if exit != 0: |
| print("child failed; expected exit code 0, got {}".format(exit)) |
| print(str(child)) |
| sys.exit(1) |