#! /usr/bin/env python3

# lDebug tests
#  2021 to 2024 by E. C. Masloch
#
# Usage of the works is permitted provided that this
# instrument is retained with the works, so that any entity
# that uses the works is notified of this instrument.
#
# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.

import sys, pty, os, time, subprocess, unittest
import fcntl, signal, pathlib, re, contextlib
import math


SCRIPTDIR = pathlib.Path(__file__).parent
build_name = os.getenv('build_name', 'debug')
booting = int(os.getenv('test_booting', '0'))
machine = os.getenv('DEFAULT_MACHINE', 'qemu')
try:
    if os.path.isfile(SCRIPTDIR / ("../tmp/qemutest/l%s.img" % build_name)):
        os.symlink("../tmp/qemutest/l%s.img" % build_name,
            SCRIPTDIR / ("l%s.img" % build_name))
except FileExistsError:
    pass
try:
    if os.path.isfile(SCRIPTDIR / ("../tmp/bdbgtest/b%s.img" % build_name)):
        os.symlink("../tmp/bdbgtest/b%s.img" % build_name,
            SCRIPTDIR / ("b%s.img" % build_name))
except FileExistsError:
    pass
try:
    if os.path.isfile(SCRIPTDIR / ("../bin/l%s.com" % build_name)):
        os.symlink("../bin/l%s.com" % build_name,
            SCRIPTDIR / ("l%s.com" % build_name))
except FileExistsError:
    pass
try:
    if os.path.isfile(SCRIPTDIR / "../bin/extlib.eld"):
        os.symlink("../bin/extlib.eld",
            SCRIPTDIR / "extlib.eld")
except FileExistsError:
    pass
if machine == 'dosemu':
    if booting:
        dpmiavailable = 0
    else:
        dpmiavailable = 1
elif machine == 'qemu':
    dpmiavailable = 0
    if not booting:
        if "x" in build_name and os.path.isfile(SCRIPTDIR / "dpmi.img"):
            dpmiavailable = 1


class InvalidVariableException(Exception):
    pass

class lDebugTest(unittest.TestCase):
    def setUp(self):
        self.debug = int(os.getenv('DEBUG', '0'))
        self.booting = int(os.getenv('test_booting', '0'))
        self.defaultsleepduration = \
            float(os.getenv('test_sleepduration', '0.05'))
        self.addsleepduration = \
            float(os.getenv('test_addsleepduration', '0.0'))
        self.dpmisubtest = 0
        machine = os.getenv('DEFAULT_MACHINE', 'qemu')
        build_name = os.getenv('build_name', 'debug')
        (self.m, s) = pty.openpty()
        self.sname = os.ttyname(s)
        os.close(s)
        self.printprogress = \
            not self.debug and \
            not (('-v' in sys.argv) or ('--verbose' in sys.argv))
        if self.debug:
            print("")
            print("sname=" + self.sname
                + " machine=" + machine
                + " build_name=" + build_name)
        if machine == 'dosemu':
            executable = os.getenv('DOSEMU', 'dosemu')
            if self.booting:
                self.dpmiavailable = 0
                command = "%s -dumb " % (executable) \
                    + " -I \'floppy { device \"%s/b%s.img\" }\' -A" % (SCRIPTDIR, build_name) \
                    + " -I \'serial { com 2 device %s }\'" % self.sname,
            else:
                self.dpmiavailable = 1
                if "x" in build_name:
                    self.dpmidir = "dpmitest\\"
                    self.dpmiexe = None
                command = "%s -dumb -K \"%s\" -E " % (executable, SCRIPTDIR) \
                    + "\'l%s.com /c=\\\"r dco or= 4000\\\"\'" % build_name \
                    + " -I \'serial { com 2 device %s }\'" % self.sname,
        elif machine == 'qemu':
            dpmiimg = ""
            self.dpmiavailable = 0
            executable = os.getenv('QEMU', 'qemu-system-i386')
            if self.booting:
                command = "%s -fda \"%s/b%s.img\"" % (executable, SCRIPTDIR, build_name) \
                    + " -boot order=a" \
                    + " -display none 2> /dev/null" \
                    + " -chardev serial,id=serial2,path=%s" % self.sname \
                    + " -serial null -serial chardev:serial2",
            else:
                if "x" in build_name and os.path.isfile(SCRIPTDIR / "dpmi.img"):
                    self.dpmidir = "b:"
                    self.dpmiexe = "b:hdpmi32.exe -r"
                    self.dpmiavailable = 1
                    dpmiimg = " -fdb \"%s/dpmi.img\"" % SCRIPTDIR
                command = "%s -fda \"%s/l%s.img\"" % (executable, SCRIPTDIR, build_name) \
                    + dpmiimg \
                    + " -boot order=a" \
                    + " -display none 2> /dev/null" \
                    + " -chardev serial,id=serial2,path=%s" % self.sname \
                    + " -serial null -serial chardev:serial2",
        else:
            os.close(self.m)
            raise InvalidVariableException("Invalid content of environment variable DEFAULT_MACHINE")
        if self.debug:
            print(command)
        fl = fcntl.fcntl(self.m, fcntl.F_GETFL)
        fcntl.fcntl(self.m, fcntl.F_SETFL, fl | os.O_NONBLOCK)
        self.vmprocess = None
        try:
            self.vmprocess = subprocess.Popen(
                command,
                shell=True,
                preexec_fn=os.setsid,
                stdin=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
                stdout=subprocess.DEVNULL)
            self.buffer = ""
            waitingseconds = 0
            while "Enter KEEP to confirm.\r" not in self.buffer:
                if self.vmprocess.poll() is not None:
                    print("vm stopped")
                    self.tearDown()
                    raise AssertionError("vm stopped")
                try:
                    self.buffer += os.read(self.m, 1).decode('cp437')
                except OSError:
                    waitingseconds += 1
                    if self.debug:
                        print("\rWaiting %s seconds" % waitingseconds, end='')
                    time.sleep(1)
            if self.debug and waitingseconds:
                print("")
            time.sleep(0.2)
            os.write(self.m, b"keep\r")
            test_initialise_commands = \
                os.getenv('test_initialise_commands', '')
            if test_initialise_commands != "":
                os.write(self.m, test_initialise_commands
                    .replace(';', '\r').encode() + b'\r')
        except KeyboardInterrupt:
            print("^C (aborting vm)")
            self.tearDown()
            raise

    def tearDown(self):
        if self.debug:
            print("tear down called")
        self.buffer = ""
        if self.booting:
            os.write(self.m, b"boot quit\r")
        else:
            os.write(self.m, b"q\r")
        time.sleep(0.05)
        if self.debug:
            self.do_read(sleepduration = None)
            print(self.buffer)
        if self.vmprocess and self.vmprocess.poll() is None:
            if self.debug:
                print("tear down terminates children")
            os.killpg(os.getpgid(self.vmprocess.pid), signal.SIGTERM)
            # self.vmprocess.terminate()
            self.vmprocess.wait()
        os.close(self.m)

    @contextlib.contextmanager
    def subtestcontext(self, *args, **kwargs):
        with self.subTest(*args, **kwargs) as var:
            try:
                if self.debug:
                    print("=== subtest: " + kwargs.get("msg", "(no message)"))
                yield var
                if self.printprogress:
                    print("#", end='', file=sys.stderr)
                    sys.stderr.flush()
            except:
                raise

    def do_read_single(self):
        try:
            input = os.read(self.m, 1).decode('cp437')
        except BlockingIOError:
            try:
                time.sleep(0.001)
                input = os.read(self.m, 1).decode('cp437')
                if self.debug:
                    print("success after sleeping")
                    sys.stdout.flush()
            except BlockingIOError:
                input = None
                pass
            except OSError:
                input = None
                pass
            pass
        except OSError:
            input = None
            pass
        return input

    def do_read(self, sleepduration = 0.0, beepreplace = '', noaddsleep = False):
        if sleepduration is not None:
            if sleepduration != 0.0:
                if noaddsleep:
                    # for timing dependent tests
                    time.sleep(sleepduration)
                else:
                    time.sleep(sleepduration + self.addsleepduration)
            else:
                time.sleep(self.defaultsleepduration)
        overwrite = 0
        linebuffer = ""
        repeat = 4
        while repeat:
            input = self.do_read_single()
            if input:
                break
            if self.debug:
                print("repeating")
                sys.stdout.flush()
            repeat -= 1
            time.sleep(0.005)
        while input:
            if overwrite:
                if input != '\n':
                    linebuffer = ""
                overwrite = 0
            if input == '\r':
                overwrite = 1
            if beepreplace is None:
                linebuffer += input
            else:
                linebuffer += input.replace('\x07', beepreplace)
            if input == '\n':
                self.buffer += linebuffer
                linebuffer = ""
            input = self.do_read_single()
        self.buffer += linebuffer

    def do_write_long(self, text, sleepduration=0.05, sleepmodulo=8):
        text = re.sub(r"[\r\n]+ +", "\r", text)
        text = re.sub(r"^\r+|\r+$", "", text)
        parts = text.split('\r')
        ii = 0
        while parts:
            ii += 1
            if (ii % sleepmodulo) == 0:
                if self.debug:
                    print("sleeping")
                time.sleep(sleepduration)
            part = parts.pop(0)
            if self.debug:
                print("appending >>%s<<" % part)
            part += '\r'
            os.write(self.m, part.encode())

    def test_beep(self):
        os.write(self.m, b"... invalid command\r")
        self.do_read(beepreplace = None)
        if self.debug:
            print(self.buffer.replace('\x07', "#BEEP#"))
        self.assertRegex(self.buffer,
            r"\r\n *\^ Error\x07\r\n")

    def test_build(self):
        os.write(self.m, b"?build\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"lDebugX? (release [0-9]+ )?\(",
            "name and opening parens not found")
        self.assertIn(
            "Source Control Revision ID",
            self.buffer,
            "id label not found")
        self.buffer = ""
        os.write(self.m, b"?version\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"lDebugX? (release [0-9]+ )?\(",
            "name and opening parens not found")
        self.assertNotIn(
            "Source Control Revision ID",
            self.buffer,
            "id label found unexpectedly")

    def test_rh(self):
        self.do_write_long("""
            install rh
            r dsr 0
            a 100
             nop
             mov cx, 100
             xor ax, ax
             xor bx, bx
             .
            r v0 aao
            a
             inc ax
             inc bx
             .
            r v1 aa0
            a
             loop (v0)
             int3
             nop
             jmp 100
             .
            g=100 v0
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +inc +ax")
        self.assertEqual(1, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"rh\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(1, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"t 3\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +inc +bx")
        self.assertRegex(self.buffer,
            r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +loop")
        self.assertRegex(self.buffer,
            r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +inc +ax")
        self.assertEqual(3, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"rh\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(4, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        self.do_write_long("""
            uninstall rh
            re.replace @r; @r ax .
            install rh
            t 3
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Error: auxbuff already guarded!", self.buffer)
        self.assertRegex(self.buffer,
            r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +inc +bx")
        self.assertRegex(self.buffer,
            r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +loop")
        self.assertRegex(self.buffer,
            r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +inc +ax")
        self.assertEqual(3, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"rh\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(3, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"r\rr\rre\rre\r")
        # r1, r2, re1, re2
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +inc +ax")
        self.assertEqual(4, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"rh\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(7, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        rhtests = [
            ("rh single 0", "rh 0", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 0", "rh,0", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 0 comma 1", "rh,0,1", "AX +[0-9A-F]{4}", 1),
            ("rh single 1", "rh 1", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 1", "rh,1", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 1 comma 1", "rh,1,1", "AX +[0-9A-F]{4}", 1),
            ("rh single 2", "rh 2", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh single comma 2", "rh,2", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh single comma 2 comma 1", "rh,2,1", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh single 3", "rh 3", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh single comma 3", "rh,3", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh single comma 3 comma 1", "rh,3,1", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh comma 0 comma 2", "rh,0,2", "AX +[0-9A-F]{4}", 1),
            ("rh comma 1 comma 2", "rh,1,2", "AX +[0-9A-F]{4}", 2),
            ("rh comma 2 comma 2", "rh,2,2", "AX +[0-9A-F]{4}", 2),
            ("rh comma 3 comma 2", "rh,3,2", "AX +[0-9A-F]{4}", 2, 1, 0),
            ("rh comma 0 comma 3", "rh,0,3", "AX +[0-9A-F]{4}", 1),
            ("rh comma 1 comma 3", "rh,1,3", "AX +[0-9A-F]{4}", 2),
            ("rh comma 2 comma 3", "rh,2,3", "AX +[0-9A-F]{4}", 3),
            ("rh comma 3 comma 3", "rh,3,3", "AX +[0-9A-F]{4}", 3),
            ("rh prepare", "t 3", ".", 3),
            # r1, r2, re1, re2, re3, re4, re5
            ("rh single 0", "rh 0", "AX +[0-9A-F]{4}", 1),	# re5
            ("rh single comma 0", "rh,0", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 0 comma 1", "rh,0,1", "AX +[0-9A-F]{4}", 1),
            ("rh single 1", "rh 1", "AX +[0-9A-F]{4}", 1),	# re4
            ("rh single comma 1", "rh,1", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 1 comma 1", "rh,1,1", "AX +[0-9A-F]{4}", 1),
            ("rh single 2", "rh 2", "AX +[0-9A-F]{4}", 1),	# re3
            ("rh single comma 2", "rh,2", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 2 comma 1", "rh,2,1", "AX +[0-9A-F]{4}", 1),
            ("rh single 3", "rh 3", "AX +[0-9A-F]{4}", 1),	# re2
            ("rh single comma 3", "rh,3", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 3 comma 1", "rh,3,1", "AX +[0-9A-F]{4}", 1),
            ("rh single 4", "rh 4", "AX +[0-9A-F]{4}", 1),	# re1
            ("rh single comma 4", "rh,4", "AX +[0-9A-F]{4}", 1),
            ("rh single comma 4 comma 1", "rh,4,1", "AX +[0-9A-F]{4}", 1),
            ("rh single 5", "rh 5", "AX +[0-9A-F]{4}", 1, 1, 0),	# r2
            ("rh single comma 5", "rh,5", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh single comma 5 comma 1", "rh,5,1", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh single 6", "rh 6", "AX +[0-9A-F]{4}", 1, 1, 0),	# r1
            ("rh single comma 6", "rh,6", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh single comma 6 comma 1", "rh,6,1", "AX +[0-9A-F]{4}", 1, 1, 0),
            ("rh comma 0 comma 2", "rh,0,2", "AX +[0-9A-F]{4}", 1),
            # re5
            ("rh comma 1 comma 2", "rh,1,2", "AX +[0-9A-F]{4}", 2),
            # re4, re5
            ("rh comma 2 comma 2", "rh,2,2", "AX +[0-9A-F]{4}", 2),
            # re3, re4
            ("rh comma 3 comma 2", "rh,3,2", "AX +[0-9A-F]{4}", 2),
            # re2, re3
            ("rh comma 4 comma 2", "rh,4,2", "AX +[0-9A-F]{4}", 2),
            # re1, re2
            ("rh comma 5 comma 2", "rh,5,2", "AX +[0-9A-F]{4}", 2),
            # r2, re1
            ("rh comma 6 comma 2", "rh,6,2", "AX +[0-9A-F]{4}", 2, 1, 0),
            # r1, r2
            ("rh comma 0 comma 3", "rh,0,3", "AX +[0-9A-F]{4}", 1),
            # re5
            ("rh comma 1 comma 3", "rh,1,3", "AX +[0-9A-F]{4}", 2),
            # re4, re5
            ("rh comma 2 comma 3", "rh,2,3", "AX +[0-9A-F]{4}", 3),
            # re3, re4, re5
            ("rh comma 3 comma 3", "rh,3,3", "AX +[0-9A-F]{4}", 3),
            # re2, re3, re4
            ("rh comma 4 comma 3", "rh,4,3", "AX +[0-9A-F]{4}", 3),
            # re1, re2, re3
            ("rh comma 5 comma 3", "rh,5,3", "AX +[0-9A-F]{4}", 3),
            # r1, re1, re2
            ("rh prepare", "qa", ".", 0),
            ("rh not empty", "rh", ".", 10),
            ("rh prepare", "uninstall rh\rinstall rh", "already disabled", 0, 1, 0),
            ("rh empty", "rh", ".", 0),
            ("rh prepare", "uninstall rh", ".", 0),
            ("rh prepare", "re.replace @if (vf) then r bx .; @if (! vf) then r cx .", ".", 0),
            ("rh prepare", "install rh", ".", 0),
            ("rh prepare", "r vf 0\rre\rre\rr vf 1\rre\rre", ".", 0),
            ("rh bx", "rh", "BX +[0-9A-F]{4}", 0),
            ("rh cx", "rh", "CX +[0-9A-F]{4}", 0),
            ("rh bx", "rh 0", "BX +[0-9A-F]{4}", 0),
            ("rh bx", "rh 1", "BX +[0-9A-F]{4}", 0),
            ("rh cx", "rh 2", "CX +[0-9A-F]{4}", 0),
            ("rh cx", "rh 3", "CX +[0-9A-F]{4}", 0),
            ("rh not cx", "rh 0", "CX +[0-9A-F]{4}", 0, 1, 0),
            ("rh not cx", "rh 1", "CX +[0-9A-F]{4}", 0, 1, 0),
            ("rh not bx", "rh 2", "BX +[0-9A-F]{4}", 0, 1, 0),
            ("rh not bx", "rh 3", "BX +[0-9A-F]{4}", 0, 1, 0),
            ]
        for tuple in rhtests:
            msg = tuple[0]
            cmd = tuple[1]
            match = tuple[2]
            amount = tuple[3]
            if len(tuple) >= 5:
                success = tuple[4]
            else:
                success = 1
            if len(tuple) >= 6:
                domatch = tuple[5]
            else:
                domatch = 1
            if len(tuple) >= 7:
                delay = tuple[6]
            else:
                delay = 0
            with self.subtestcontext(msg = msg + ": " + cmd.replace("\r","##")):
                if self.debug:
                    print(self.buffer)
                    print("msg=%s cmd=%s match=%s amount=%d success=%d domatch=%d"
                        % (msg, cmd.replace("\r","##"),
                            match.replace("\r","##").replace("\n","%%"),
                            amount, success, domatch))
                self.buffer = ""
                actuallysucceeded = 0
                try:
                    os.write(self.m, ("%s\r" % cmd).encode())
                    if delay:
                        time.sleep(0.05)
                    self.do_read()
                    self.assertNotRegex(self.buffer,
                        r"\^ Error",
                        "error in command")
                    if domatch:
                        self.assertRegex(self.buffer,
                            match,
                            "match mismatch")
                    else:
                        self.assertNotRegex(self.buffer,
                            match,
                            "unexpected match")
                    self.assertEqual(amount, len(re.findall(
                        r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)),
			"wrong amount")
                    actuallysucceeded = 1
                except AssertionError as e:
                    if success:
                        raise e
                    else:
                        if self.debug:
                            print("passing on upon AssertionError(\""
                                + str(e) + "\")")
                        pass
                if actuallysucceeded and not success:
                    raise AssertionError("unexpected success")
        if self.debug:
            print(self.buffer)
        self.buffer = ""

    def test_dt(self):
        os.write(self.m, b"dt\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"dt[\r\n]+(Dec Hex\s*){8}[\r\n]",
            "DT header not found")
        self.assertRegex(self.buffer,
            r"Dec Hex[\r\n]+((\s*[0-9]+\s+[0-9A-F]{2}\s+[A-Z0-9]{2,3}){2}"
            + r"(\s+[0-9]+\s+[0-9A-F]{2}\s+.){6}[\r\n]+){1}",
            "DT first line not found")
        self.assertRegex(self.buffer,
            r"Dec Hex[\r\n]+((\s*[0-9]+\s+[0-9A-F]{2}\s+[A-Z0-9]{2,3}){2}"
            + r"(\s+[0-9]+\s+[0-9A-F]{2}\s+(.|DEL)){6}"
            + r"[\r\n]+){16}",
            "DT table not found")
        self.buffer = ""
        os.write(self.m, b"dt #'ecm!'\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"[\r\n]+\s*[0-9]+\s+[0-9A-F]{2}\s+'e'"
            + r"\s\s+[0-9]+\s+[0-9A-F]{2}\s+'c'"
            + r"\s\s+[0-9]+\s+[0-9A-F]{2}\s+'m'"
            + r"\s\s+[0-9]+\s+[0-9A-F]{2}\s+'!'"
            + r"[\r\n]+", "unexpected output of DT command")
        self.buffer = ""
        os.write(self.m, b"dt 80_00\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"[\r\n]+\s*0\s+00\s+NUL"
            + r"\s\s+[0-9]+\s+[0-9A-F]{2}\s+top"
            + r"[\r\n]+", "unexpected output of DT command")
        self.buffer = ""
        os.write(self.m, b"dt,3\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"[\r\n]+\s*3\s+03\s+ETX"
            + r"[\r\n]+", "unexpected output of DT command")
        self.buffer = ""
        os.write(self.m, b"dt op\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertIn("^ Error", self.buffer)

    def test_rr_status(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
            self.buffer = ""
        os.write(self.m, b"a\r")
        self.do_read()
        self.assertRegex(self.buffer,
            r"(?m)^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{4,8} ",
            "assembly aa prompt not found")
        os.write(self.m, b".\r")
        self.do_read()
        self.buffer = ""
        os.write(self.m, b"r ip := 100\rf cs:ip l 10 90\r")
        self.do_read()
        self.assertNotIn("^ Error", self.buffer)
        rrtests = [
            ("test rr jumping", "jo 100",   "70FE", "r efl := 0", "  not jumping"),
            ("test rr jumping", "jno 100",  "71FE", "r efl := 0", "  jumping"),
            ("test rr jumping", "jc 100",   "72FE", "r efl := 0", "  not jumping"),
            ("test rr jumping", "jnc 100",  "73FE", "r efl := 0", "  jumping"),
            ("test rr jumping", "je 100",   "74FE", "r efl := 0", "  not jumping"),
            ("test rr jumping", "jne 100",  "75FE", "r efl := 0", "  jumping"),
            ("test rr jumping", "jbe 100",  "76FE", "r efl := 0", "  not jumping"),
            ("test rr jumping", "jnbe 100", "77FE", "r efl := 0", "  jumping"),
            ("test rr jumping", "js 100",   "78FE", "r efl := 0", "  not jumping"),
            ("test rr jumping", "jns 100",  "79FE", "r efl := 0", "  jumping"),
            ("test rr jumping", "jp 100",   "7AFE", "r efl := 0", "  not jumping"),
            ("test rr jumping", "jnp 100",  "7BFE", "r efl := 0", "  jumping"),
            ("test rr jumping", "jl 100",   "7CFE", "r efl := 0", "  not jumping"),
            ("test rr jumping", "jnl 100",  "7DFE", "r efl := 0", "  jumping"),
            ("test rr jumping", "jle 100",  "7EFE", "r efl := 0", "  not jumping"),
            ("test rr jumping", "jnle 100", "7FFE", "r efl := 0", "  jumping"),
            ("test rr jumping", "jo 100",   "70FE", "r efl := -1", "  jumping"),
            ("test rr jumping", "jno 100",  "71FE", "r efl := -1", "  not jumping"),
            ("test rr jumping", "jc 100",   "72FE", "r efl := -1", "  jumping"),
            ("test rr jumping", "jnc 100",  "73FE", "r efl := -1", "  not jumping"),
            ("test rr jumping", "je 100",   "74FE", "r efl := -1", "  jumping"),
            ("test rr jumping", "jne 100",  "75FE", "r efl := -1", "  not jumping"),
            ("test rr jumping", "jbe 100",  "76FE", "r efl := -1", "  jumping"),
            ("test rr jumping", "jnbe 100", "77FE", "r efl := -1", "  not jumping"),
            ("test rr jumping", "js 100",   "78FE", "r efl := -1", "  jumping"),
            ("test rr jumping", "jns 100",  "79FE", "r efl := -1", "  not jumping"),
            ("test rr jumping", "jp 100",   "7AFE", "r efl := -1", "  jumping"),
            ("test rr jumping", "jnp 100",  "7BFE", "r efl := -1", "  not jumping"),
            ("test rr jumping", "jl 100",   "7CFE", "r efl := -1", "  not jumping"),
            ("test rr jumping", "jnl 100",  "7DFE", "r efl := -1", "  jumping"),
            ("test rr jumping", "jle 100",  "7EFE", "r efl := -1", "  jumping"),
            ("test rr jumping", "jnle 100", "7FFE", "r efl := -1", "  not jumping"),
            ("test rr jumping", "jcxz 100", "E3FE", "r ecx := 1", "  not jumping"),
            ("test rr jumping", "jcxz 100", "E3FE", "r ecx := 0", "  jumping"),
            ("test rr jumping", "jcxz 100", "E3FE", "r ecx := 1_0000", "  jumping"),
            ("test rr jumping", "jecxz 100", "67E3FD", "r ecx := 1", "  not jumping"),
            ("test rr jumping", "jecxz 100", "67E3FD", "r ecx := 0", "  jumping"),
            ("test rr jumping", "jecxz 100", "67E3FD", "r ecx := 1_0000", "  not jumping"),
            ("test rr jumping", "loopz 100", "E1FE", \
                "r ecx := 1\rr efl := -1", "  not jumping"),
            ("test rr jumping", "loopz 100", "E1FE", \
                "r ecx := 0\rr efl := -1", "  jumping"),
            ("test rr jumping", "loopz 100", "E1FE", \
                "r ecx := 1_0001\rr efl := -1", "  not jumping"),
            ("test rr jumping", "loopzd 100", "67E1FD", \
                "r ecx := 1\rr efl := -1", "  not jumping"),
            ("test rr jumping", "loopzd 100", "67E1FD", \
                "r ecx := 0\rr efl := -1", "  jumping"),
            ("test rr jumping", "loopzd 100", "67E1FD", \
                "r ecx := 1_0001\rr efl := -1", "  jumping"),
            ("test rr jumping", "loopnz 100", "E0FE", \
                "r ecx := 1\rr efl := 0", "  not jumping"),
            ("test rr jumping", "loopnz 100", "E0FE", \
                "r ecx := 0\rr efl := 0", "  jumping"),
            ("test rr jumping", "loopnz 100", "E0FE", \
                "r ecx := 1_0001\rr efl := 0", "  not jumping"),
            ("test rr jumping", "loopnzd 100", "67E0FD", \
                "r ecx := 1\rr efl := 0", "  not jumping"),
            ("test rr jumping", "loopnzd 100", "67E0FD", \
                "r ecx := 0\rr efl := 0", "  jumping"),
            ("test rr jumping", "loopnzd 100", "67E0FD", \
                "r ecx := 1_0001\rr efl := 0", "  jumping"),
            ("test rr jumping", "loop 100", "E2FE", \
                "r ecx := 1", "  not jumping"),
            ("test rr jumping", "loop 100", "E2FE", \
                "r ecx := 0", "  jumping"),
            ("test rr jumping", "loop 100", "E2FE", \
                "r ecx := 1_0001", "  not jumping"),
            ("test rr jumping", "loopd 100", "67E2FD", \
                "r ecx := 1", "  not jumping"),
            ("test rr jumping", "loopd 100", "67E2FD", \
                "r ecx := 0", "  jumping"),
            ("test rr jumping", "loopd 100", "67E2FD", \
                "r ecx := 1_0001", "  jumping"),
            ("test rr flags", "nop", "90", \
                "r f NC", " NC"),
            ("test rr flags", "nop", "90", \
                "r f CY", " CY"),
            ("test rr flags", "nop", "90", \
                "r fl and:= ~1", " NC"),
            ("test rr flags", "nop", "90", \
                "r fl or:= 1", " CY"),
            ("test rr flags", "nop", "90", \
                "r f NZ", " NZ "),
            ("test rr flags", "nop", "90", \
                "r f ZR", " ZR "),
            ("test rr flags", "nop", "90", \
                "r fl and:= ~40", " NZ "),
            ("test rr flags", "nop", "90", \
                "r fl or:= 40", " ZR "),
            ("test rr mem", "mov ax, word [cs:100]", "2EA10001", \
                "; none", " CS:0100=A12E\r\n"),
            ("test rr mem", "mov word [cs:100], ax", "2EA30001", \
                "; none", " CS:0100=A32E\r\n"),
            ("test rr 386", "mov eax, eax", "6689C0", \
                "m 0", " [needs 386]"),
            ("test rr 386", "mov eax, dword [cs:100]", "662EA10001", \
                "m 0", " [needs 386]"),
            ("test rr 386", "mov ax, word [cs:dword 100]", "672EA100010000", \
                "m 0", " [needs 386]"),
            ]
        for tuple in rrtests:
            msg = tuple[0]
            inst = tuple[1]
            code = tuple[2]
            setup = tuple[3]
            match = tuple[4]
            if len(tuple) >= 6:
                success = tuple[5]
            else:
                success = 1
            if len(tuple) >= 7:
                delay = tuple[6]
            else:
                delay = 0
            with self.subtestcontext(msg = msg + ": " + inst):
                if self.debug:
                    print(self.buffer)
                    print("msg=%s inst=%s code=%s success=%d"
                        % (msg, inst, code, success))
                self.buffer = ""
                actuallysucceeded = 0
                try:
                    os.write(self.m, ("a 100\r%s\r.\r" % inst).encode())
                    os.write(self.m, ("%s\r" % setup).encode())
                    os.write(self.m, b"r\r")
                    if delay:
                        time.sleep(0.05)
                    self.do_read()
                    self.assertNotRegex(self.buffer,
                        r"\^ Error",
                        "error in assembling")
                    self.assertRegex(self.buffer,
                        r"\r\n[0-9A-Fa-f:]{9,13} %s " % code,
                        "code mismatch")
                    self.assertRegex(self.buffer,
                        match,
                        "status mismatch")
                    actuallysucceeded = 1
                except AssertionError as e:
                    if success:
                        raise e
                    else:
                        if self.debug:
                            print("passing on upon AssertionError(\""
                                + str(e) + "\")")
                        pass
                if actuallysucceeded and not success:
                    raise AssertionError("unexpected success")
        if self.debug:
            print(self.buffer)

    def test_aa_basic(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
            self.buffer = ""
        os.write(self.m, b"a\r")
        self.do_read()
        self.assertRegex(self.buffer,
            r"(?m)^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{4,8} ",
            "assembly aa prompt not found")
        os.write(self.m, b".\r")
        self.do_read()
        asmtests = [
            ("test aa", "nop", ".*"),
            ("test aa", "nop", "90"),
            ("test aa", "mov ax, 0", "B80000", 1, 0, "o16"),
            ("test aa", "mov ax, 1234", "B83412", 1, 0, "o16"),
            ("test aa", "mov ax, (26)", "B82600", 1, 0, "o16"),
            ("test aa", "mov ax, (#38)", "B82600", 1, 0, "o16"),
            ("test aa", "jmp 100", "EBFE"),
            ("test aa", "jmp near 100", "E9FDFF", 1, 0, "86m16"),
            ("test aa", "jmp near 100", "E9FBFFFFFF", 1, 0, "pm32"),
            ("test aa fail", "jmp near 100", "90", 0),
            ("test aa fail", "jmp xyz", ".*", 0),
            ("test aa", "push +1", "6A01"),
            ("test aa", "pushw +1", "6A01", 1, 0, "o16"),
            ("test aa", "pushd +1", "6A01", 1, 0, "o32"),
            ("test aa", "push byte +1", "6A01"),
            ("test aa", "pushw byte +1", "6A01", 1, 0, "o16"),
            ("test aa", "pushd byte +1", "6A01", 1, 0, "o32"),
            ("test aa", "push word +1", "680100", 1, 0, "o16"),
            ("test aa", "push dword +1", "6801000000", 1, 0, "o32"),
            ("test aa", "pushw word +1", "680100", 1, 0, "o16"),
            ("test aa", "pushd dword +1", "6801000000", 1, 0, "o32"),
            ("test aa fail", "pushd word +1", ".*", 0),
            ("test aa fail", "pushw dword +1", ".*", 0),
            ("test aa", "push +123", "682301", 1, 0, "86m16"),
            ("test aa", "push +123", "6823010000", 1, 0, "pm32"),
            ("test aa", "pushw +123", "682301", 1, 0, "o16"),
            ("test aa", "pushd +123", "6823010000", 1, 0, "o32"),
            ("test aa fail", "push byte +123", ".*", 0),
            ("test aa fail", "pushw byte +123", ".*", 0),
            ("test aa fail", "pushd byte +123", ".*", 0),
            ("test aa", "push word +123", "682301", 1, 0, "o16"),
            ("test aa", "push dword +123", "6823010000", 1, 0, "o32"),
            ("test aa", "pushw word +123", "682301", 1, 0, "o16"),
            ("test aa", "pushd dword +123", "6823010000", 1, 0, "o32"),
            ("test aa fail", "pushd word +123", ".*", 0),
            ("test aa fail", "pushw dword +123", ".*", 0),
            ("test aa fail", "add [100], 12", ".*", 0),
            ("test aa", "loop 100", "E2FE"),
            ("test aa", "loopz 100", "E1FE"),
            ("test aa", "loopnz 100", "E0FE"),
            ("test aa", "loopw 100", "E2F[DE]", 1, 0, "a16"),
            ("test aa", "loopzw 100", "E1F[DE]", 1, 0, "a16"),
            ("test aa", "loopnzw 100", "E0F[DE]", 1, 0, "a16"),
            ("test aa", "loopd 100", "E2F[DE]", 1, 0, "a32"),
            ("test aa", "loopzd 100", "E1F[DE]", 1, 0, "a32"),
            ("test aa", "loopnzd 100", "E0F[DE]", 1, 0, "a32"),
            ("test aa", "loop 100, cx", "E2F[DE]", 1, 0, "a16"),
            ("test aa", "loopz 100, cx", "E1F[DE]", 1, 0, "a16"),
            ("test aa", "loopnz 100, cx", "E0F[DE]", 1, 0, "a16"),
            ("test aa fajl", "loopw 100, cx", ".*", 0),
            ("test aa fail", "loopzw 100, cx", ".*", 0),
            ("test aa fail", "loopnzw 100, cx", ".*", 0),
            ("test aa fail", "loopd 100, cx", ".*", 0),
            ("test aa fail", "loopzd 100, cx", ".*", 0),
            ("test aa fail", "loopnzd 100, cx", ".*", 0),
            ("test aa", "loop 100, ecx", "E2F[DE]", 1, 0, "a32"),
            ("test aa", "loopz 100, ecx", "E1F[DE]", 1, 0, "a32"),
            ("test aa", "loopnz 100, ecx", "E0F[DE]", 1, 0, "a32"),
            ("test aa fail", "loopw 100, ecx", ".*", 0),
            ("test aa fail", "loopzw 100, ecx", ".*", 0),
            ("test aa fail", "loopnzw 100, ecx", ".*", 0),
            ("test aa fail", "loopd 100, ecx", ".*", 0),
            ("test aa fail", "loopzd 100, ecx", ".*", 0),
            ("test aa fail", "loopnzd 100, ecx", ".*", 0),
            ("test aa", "int3", "CC"),
            ("test aa", "int 3", "CC"),
            ("test aa", "int byte 3", "CD03"),
            ("test aa", "ret", "C3"),
            ("test aa", "retn", "C3"),
            ("test aa", "retf", "CB"),
            ("test aa", "ret 8", "C20800"),
            ("test aa", "retn 8", "C20800"),
            ("test aa", "retf 8", "CA0800"),
            ("test aa", "retw", "C3", 1, 0, "o16"),
            ("test aa", "retnw", "C3", 1, 0, "o16"),
            ("test aa", "retfw", "CB", 1, 0, "o16"),
            ("test aa", "retw 8", "C20800", 1, 0, "o16"),
            ("test aa", "retnw 8", "C20800", 1, 0, "o16"),
            ("test aa", "retfw 8", "CA0800", 1, 0, "o16"),
            ("test aa", "retd", "C3", 1, 0, "o32"),
            ("test aa", "retnd", "C3", 1, 0, "o32"),
            ("test aa", "retfd", "CB", 1, 0, "o32"),
            ("test aa", "retd 8", "C20800", 1, 0, "o32"),
            ("test aa", "retnd 8", "C20800", 1, 0, "o32"),
            ("test aa", "retfd 8", "CA0800", 1, 0, "o32"),
            ("test aa fail", "ret 10000", ".*", 0),
            ("test aa fail", "retn 10000", ".*", 0),
            ("test aa fail", "retf 10000", ".*", 0),
            ("test aa fail", "retw 10000", ".*", 0),
            ("test aa fail", "retnw 10000", ".*", 0),
            ("test aa fail", "retfw 10000", ".*", 0),
            ("test aa fail", "retd 10000", ".*", 0),
            ("test aa fail", "retnd 10000", ".*", 0),
            ("test aa fail", "retfd 10000", ".*", 0),
            ("test aa", "mov ax, 1_00", "B80001", 1, 0, "o16"),
            ]
        for tuple in asmtests:
            msg = tuple[0]
            inst = tuple[1]
            code = tuple[2]
            if len(tuple) >= 4:
                success = tuple[3]
            else:
                success = 1
            if len(tuple) >= 5:
                delay = tuple[4]
            else:
                delay = 0
            if len(tuple) >= 6:
                sizeprefix = tuple[5]
            else:
                sizeprefix = ""
            with self.subtestcontext(msg = msg + ": " + inst):
                if self.debug:
                    print(self.buffer)
                    print("msg=%s inst=%s code=%s success=%d sizeprefix=\"%s\""
                        % (msg, inst, code, success, sizeprefix))
                self.buffer = ""
                actuallysucceeded = 0
                try:
                    os.write(self.m, ("a 100\r%s\r.\r" % inst).encode())
                    os.write(self.m, b"u 100 l 1\r")
                    if delay:
                        time.sleep(0.05)
                    self.do_read()
                    self.assertNotRegex(self.buffer,
                        r"\^ Error",
                        "error in assembling")
                    asize=""
                    osize=""
                    if self.dpmisubtest:
                        if "a16" in sizeprefix:
                            asize="67"
                        if "o16" in sizeprefix:
                            osize="66"
                        if "86m16" in sizeprefix:
                            success=0
                            raise AssertionError("86 Mode only test")
                    else:
                        if "a32" in sizeprefix:
                            asize="67"
                        if "o32" in sizeprefix:
                            osize="66"
                        if "pm32" in sizeprefix:
                            success=0
                            raise AssertionError("PM32 only test")
                    self.assertRegex(self.buffer,
                        r"\r\n[0-9A-Fa-f:]{9,13} %s%s%s " % (asize, osize, code),
                        "code mismatch")
                    actuallysucceeded = 1
                except AssertionError as e:
                    if success:
                        raise e
                    else:
                        if self.debug:
                            print("passing on upon AssertionError(\""
                                + str(e) + "\")")
                        pass
                if actuallysucceeded and not success:
                    raise AssertionError("unexpected success")
        if self.debug:
            print(self.buffer)

    def test_rr_basic(self):
        self.do_read()
        rrtests = [
            ("test rr", "r ax := 1", "ax", ".*"),
            ("test rr", "r ax := 1", "ax", "1"),
            ("test rr", "r ax +:= 1", "ax", "2"),
            ("test rr", "r word [cs:ip] := 9090", "word [cs:ip]", "9090"),
            ("test rr fail", "r ax := 0", "ax", "FFFF", 0),
            ("test rr fail", "r ax := baz", "ax", ".*", 0),
            ("test rr double 1", "r bxcx := 1234_5678", "cx", "5678"),
            ("test rr double 2", "; nothing", "bx", "1234"),
            ("test expr basic", "r v0 := 2 * 3 + 4", "v0", "A"),
            ("test expr parens", "r v0 := 2 * (3 + 4)", "v0", "E"),
            ("test expr bitmirror", "r v0 := AA >< 8", "v0", "55"),
            ("test expr value in", "r v0 :="
                + " VALUE 26 IN 26, 26, FROM 20 TO 26,"
                + " FROM 26 LENGTH 1, 38, AA55", "v0", "4", 1, 2),
            ("test expr division error", "r v0 := 1 / 0", "v0", ".*", 0),
            ("test expr mismatch", "r v0 := 1", "v0", "0", 0),
            ("test expr overflow", "r v0 := #4294967296", "v0", ".*", 0),
            ("test expr conditional", "r v0 := 1 ?? 4 :: 8", "v0", "4"),
            ("test expr conditional", "r v0 := 0 ?? 4 :: 8", "v0", "8"),
            ("test expr conditional", "r v0 := 0 ?? 4 :: 1 ?? 8 :: 10", "v0", "8"),
            ("test expr conditional", "r v0 := 0 ?? 4 :: 0 ?? 8 :: 10", "v0", "10"),
            ("test expr conditional", "r v0 := 1 ?? 0 ?? 8 :: 10 :: 20", "v0", "10"),
            ("test expr conditional", "r v0 := 1 ?? 1 ?? 8 :: 10 :: 20", "v0", "8"),
            ("test rr", "r ax := #'A1'", "ax", "3141"),
            ("test rr", 'r ax := #"A1"', "ax", "3141"),
            ("test rr", 'r eax := #"321"', "eax", "00313233"),
            ("test rr fail", 'r eax := #"1', "eax", ".*", 0),
            ("test rr fail", 'r eax := #""', "eax", "0+"),
            ("test rr", "r dword [cs:ip] := 90909090", "dword [cs:ip]", "90909090"),
            ("test rr", "r 3byte [cs:ip] := 112233", "3byte [cs:ip]", "112233"),
            ("test rr", "; nothing", "byte [cs:ip + 3]", "90"),
            ("test rr", "r word [cs:ip] := 1122", "word [cs:ip]", "1122"),
            ("test rr", "; nothing", "word [cs:ip + 2]", "9011"),
            ("test rr", "r byte [cs:ip] := 11", "byte [cs:ip]", "11"),
            ("test rr", "; nothing", "3byte [cs:ip + 1]", "901111"),
            ]
        for tuple in rrtests:
            msg = tuple[0]
            cmd = tuple[1]
            var = tuple[2]
            value = tuple[3]
            if len(tuple) >= 5:
                success = tuple[4]
            else:
                success = 1
            if len(tuple) >= 6:
                delay = tuple[5]
            else:
                delay = 0
            with self.subtestcontext(msg = msg + ": " + cmd):
                if self.debug:
                    print(self.buffer)
                    print("msg=%s cmd=%s var=%s value=%s success=%d"
                        % (msg, cmd, var, value, success))
                self.buffer = ""
                actuallysucceeded = 0
                try:
                    os.write(self.m, ("%s\r" % cmd).encode())
                    os.write(self.m, ("r %s .\r" % var).encode())
                    if delay:
                        time.sleep(0.05 * delay)
                    self.do_read()
                    self.assertNotRegex(self.buffer,
                        r"\^ Error",
                        "error in command")
                    self.assertRegex(self.buffer,
                        r"\r\n[\]\[: A-Za-z0-9]+ 0*%s\r\n" % value,
                        "value mismatch")
                    actuallysucceeded = 1
                except AssertionError as e:
                    if success:
                        raise e
                    else:
                        if self.debug:
                            print("passing on upon AssertionError(\""
                                + str(e) + "\")")
                        pass
                if actuallysucceeded and not success:
                    raise AssertionError("unexpected success")
        if self.debug:
            print(self.buffer)

    def test_misc(self):
        self.do_read()
        misctests = [
            ("ss", "f 100 l 80 0\r"
                + "s 100 l 10 0", "\r\n0010 matches\r\n"),
            ("post ss", "r src .", "\r\nSRC 0*10\r\n"),
            ("post ss", "r sro .", "\r\nSRO 0*100\r\n"),
            ("post ss", "r sro0 .", "\r\nSRO0 0*100\r\n"),
            ("post ss", "r sro1 .", "\r\nSRO1 0*101\r\n"),
            ("post ss", "h srs == ds", "\r\n0*1  decimal:.*\r\n"),
            ("setup for dd", "r dx 100", "."),
            ("setup for dd", "r cx linear ds:0, >> 4", "."),
            ("dd", "dtop 100", "\r\n([0-9A-Fa-f]{4}:01[0-7]0  (00[- ]){16}.{16}\r\n){8}"),
            ("dd", "d,top,100", "\r\n([0-9A-Fa-f]{4}:01[0-7]0  (00[- ]){16}.{16}\r\n){8}"),
            ("dd", "d 100 l 10", "\r\n[0-9A-Fa-f]{4}:0100  (00[- ]){16}.{16}\r\n"),
            ("dd", "d $cx:100 l 10", "\r\n[0-9A-Fa-f]{4}:0100  (00[- ]){16}.{16}\r\n"),
            ("dd", "d 100 ; comment", "\r\n([0-9A-Fa-f]{4}:01[0-7]0  (00[- ]){16}.{16}\r\n){8}"),
            ("dd", "d ptr dsdx l 10", "\r\n[0-9A-Fa-f]{4}:0100  (00[- ]){16}.{16}\r\n"),
            ("dd", "d pointer dsdx l 10", "\r\n[0-9A-Fa-f]{4}:0100  (00[- ]){16}.{16}\r\n"),
            ("dd", "d ptr dsdx", "\r\n([0-9A-Fa-f]{4}:01[0-7]0  (00[- ]){16}.{16}\r\n){8}"),
            ("dd", "d $ ptr cxdx l 10", "\r\n[0-9A-Fa-f]{4}:0100  (00[- ]){16}.{16}\r\n"),
            ("dd", "d $ pointer cxdx l 10", "\r\n[0-9A-Fa-f]{4}:0100  (00[- ]){16}.{16}\r\n"),
            ("dd", "d $ ptr cxdx", "\r\n([0-9A-Fa-f]{4}:01[0-7]0  (00[- ]){16}.{16}\r\n){8}"),
            ("dd", "d ds:ptr dsdx", ".", 0),
            ("dd", "d ds:ptr dx", ".", 0),
            ("dd", "d ds:dx ptr 10F", ".", 0),
            ("dd", "d ds:pointer dsdx", ".", 0),
            ("dd", "d ds:pointer dx", ".", 0),
            ("dd", "d ds:dx pointer 10F", ".", 0),
            ("vars", "r dco .", "."),
            ("vars", "r dco0 .", ".", 0),
            ("vars", "r dco1 .", "."),
            ("vars", "r dco2 .", "."),
            ("vars", "r dco3 .", "."),
            ("vars", "r dco4 .", "."),
            ("vars", "r dco5 .", "."),
            ("vars", "r dco6 .", "."),
            ("vars", "r dco7 .", "."),
            ("vars", "r dco8 .", ".", 0),
            ("vars", "r dif .", "."),
            ("vars", "r dif0 .", ".", 0),
            ("vars", "r dif1 .", "."),
            ("vars", "r dif2 .", "."),
            ("vars", "r dif3 .", "."),
            ("vars", "r dif4 .", "."),
            ("vars", "r dif5 .", "."),
            ("vars", "r dif6 .", "."),
            ("vars", "r dif7 .", "."),
            ("vars", "r dif8 .", ".", 0),
            ("hh", "h base=#10 18", "\r\n24\r\n"),
            ("hh", "h base=#10 group=3 400", "\r\n1_024\r\n"),
            ("hh", "h base=#2 group=4 AA55", "\r\n1010_1010_0101_0101\r\n"),
            ("hh", "h base=#2 group=4 width=10 1138", "\r\n0001_0001_0011_1000\r\n"),
            ("hh", "h linear $1234:5", "\r\n0*12345 "),
            ("hh", "h linear $1000:2345", "\r\n0*12345 "),
            ("hh", "h 2 +1", "\r\n0*3  decimal:"),
            ("hh", "h 2, +1", "\r\n0*3  0*1\r\n"),
            ("hh", "h 2,, +1", ".", 0),
            ("hh", "h base=10 2, +1", ".", 0),
            ("hh", "h ri2Do == word [$0:2D*4]", "\r\n0*1  decimal:"),
            ("hh", "h ri2Ds == word [$0:2D*4 + 2]", "\r\n0*1  decimal:"),
            ("hh", "h ri2Dl == linear $word [$0:2D*4 + 2]:word [$0:2D*4]", "\r\n0*1  decimal:", 1, 1),
            ("hh", "h ri2Dl == linear $ri2Ds:ri2Do", "\r\n0*1  decimal:", 1, 1),
            ("psp var", "h segment ppi == dpr || dif & 4000", "\r\n0*1  decimal:"),
            ("psp var", "h ppr == dpr || dif & 4000", "\r\n0*1  decimal:"),
            ("psp var", "h psp != 0 || dif & 4000", "\r\n0*1  decimal:"),
            ("psp var", "h (linear psps:0) == (psp << 4) || dif & 4000", "\r\n0*1  decimal:", 1, 1),
            ("psp var", "h ppi == 0 || !(dif & 4000)", "\r\n0*1  decimal:"),
            ("psp var", "h ppr == 0 || !(dif & 4000)", "\r\n0*1  decimal:"),
            ("psp var", "h psp == 0 || !(dif & 4000)", "\r\n0*1  decimal:"),
            ("reg var", "h al", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ah", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ax", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h eax", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h bl", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h bh", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h bx", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ebx", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h cl", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ch", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h cx", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ecx", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h dl", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h dh", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h dx", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h edx", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h di", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h edi", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h si", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h esi", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h bp", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ebp", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h sp", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h esp", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ip", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h eip", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h fl", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h efl", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h cs", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ds", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h es", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ss", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h fs", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h gs", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h dxax", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h bxcx", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h csip", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h sssp", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h dssi", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h esdi", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h dsdx", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h sidi", "\r\n[0-9A-Fa-f]*  decimal:"),
            ("reg var", "h ds00", "\r\n[0-9A-Fa-f]+0000  decimal:"),
            ("reg var equal", "h dxax == dx * 10000 + ax", "\r\n0*1  decimal:"),
            ("reg var equal", "h bxcx == bx * 10000 + cx", "\r\n0*1  decimal:"),
            ("reg var equal", "h csip == cs * 10000 + ip", "\r\n0*1  decimal:"),
            ("reg var equal", "h sssp == ss * 10000 + sp", "\r\n0*1  decimal:"),
            ("reg var equal", "h dssi == ds * 10000 + si", "\r\n0*1  decimal:"),
            ("reg var equal", "h esdi == es * 10000 + di", "\r\n0*1  decimal:"),
            ("reg var equal", "h dsdx == ds * 10000 + dx", "\r\n0*1  decimal:"),
            ("reg var equal", "h sidi == si * 10000 + di", "\r\n0*1  decimal:"),
            ("reg var equal", "h ds00 == ds * 10000 + 0", "\r\n0*1  decimal:"),
            ("rr limit", "r ax 0", "."),
            ("rr limit", "r ax 1", "."),
            ("rr limit", "r ax -1", "."),
            ("rr limit", "r ax 7FFF", "."),
            ("rr limit", "r ax FFFF", "."),
            ("rr limit", "r ax 10000", ".", 0),
            ("rr limit", "r ax -8000", "."),
            ("rr limit", "r ax -8001", ".", 0),
            ("rr limit", "r ax FFFF_FFFF", ".", 0),
            ("rr limit", "r word [F0] 0", "."),
            ("rr limit", "r word [F0] 1", "."),
            ("rr limit", "r word [F0] -1", "."),
            ("rr limit", "r word [F0] 7FFF", "."),
            ("rr limit", "r word [F0] FFFF", "."),
            ("rr limit", "r word [F0] 10000", ".", 0),
            ("rr limit", "r word [F0] -8000", "."),
            ("rr limit", "r word [F0] -8001", ".", 0),
            ("rr limit", "r word [F0] FFFF_FFFF", ".", 0),
            ]
        for tuple in misctests:
            msg = tuple[0]
            cmd = tuple[1]
            match = tuple[2]
            if len(tuple) >= 4:
                success = tuple[3]
            else:
                success = 1
            if len(tuple) >= 5:
                delay = tuple[4]
            else:
                delay = 0
            with self.subtestcontext(msg = msg + ": " + cmd.replace("\r","##")):
                if self.debug:
                    print(self.buffer)
                    print("msg=%s cmd=%s match=%s success=%d"
                        % (msg, cmd.replace("\r","##"),
                            match.replace("\r","##").replace("\n","%%"),
                            success))
                self.buffer = ""
                actuallysucceeded = 0
                try:
                    os.write(self.m, ("%s\r" % cmd).encode())
                    if delay:
                        time.sleep(0.05)
                    self.do_read()
                    self.assertNotRegex(self.buffer,
                        r"\^ Error",
                        "error in command")
                    self.assertRegex(self.buffer,
                        match,
                        "match mismatch")
                    actuallysucceeded = 1
                except AssertionError as e:
                    if success:
                        raise e
                    else:
                        if self.debug:
                            print("passing on upon AssertionError(\""
                                + str(e) + "\")")
                        pass
                if actuallysucceeded and not success:
                    raise AssertionError("unexpected success")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "autorepeat tt test"):
            self.do_write_long("""
                r dco3 and= ~ 1000_0000  ; enable autorepeat
                a 100
                 nop
                 nop
                 inc ax
                 int3
                 .
                t=100
                """)
            os.write(self.m, b"\r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f]{4}:(0000)?0102 +(66)?40 +inc +ax")
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"; empty\r\r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotRegex(self.buffer,
                r"\r\n[0-9A-Fa-f]{4}:[0-9A-Fa-f]{4,8} ")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "autorepeat tt with blanks test"):
            self.do_write_long("""
                r dco3 and= ~ 1000_0000  ; enable autorepeat
                a 100
                 nop
                 nop
                 inc ax
                 int3
                 .
                t=100
                """)
            os.write(self.m, b"  \r")
            self.do_read(sleepduration = 0.2)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f]{4}:(0000)?0102 +(66)?40 +inc +ax")
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"  ; empty\r  \r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotRegex(self.buffer,
                r"\r\n[0-9A-Fa-f]{4}:[0-9A-Fa-f]{4,8} ")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "autorepeat disable tt test"):
            self.do_write_long("""
                r dco3 or= 1000_0000  ; disable autorepeat
                a 100
                 nop
                 nop
                 inc ax
                 int3
                 .
                t=100
                """)
            os.write(self.m, b"\r")
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f]{4}:0102 +40 +inc +ax")
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"; empty\r\r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotRegex(self.buffer,
                r"\r\n[0-9A-Fa-f]{4}:[0-9A-Fa-f]{4,8} ")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "hh no overflow test"):
            levels = 12
            # this number of parens appears to work on lDDebug and lDebug
            os.write(self.m, ("h " + levels * "(" + "1" + levels * ")" + "\r").encode())
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotIn("Stack overflow occurred", self.buffer)
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "hh overflow test"):
            levels = 48
            # this number of parens appears to fail on all builds
            os.write(self.m, ("h " + levels * "(" + "1" + levels * ")" + "\r").encode())
            self.do_read(sleepduration = 0.2)
            self.assertNotIn("^ Error", self.buffer)
            self.assertIn("Stack overflow occurred", self.buffer)
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "register change highlighting test"):
            os.write(self.m, b"r dco3 or= 4_0000\rr\rr ax ^:= word -1\r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.buffer = ""
            os.write(self.m, b"r\r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?i)AX *= *\x1B\[7m[0-9A-Fa-f]{4,8}\x1B\[m")
        os.write(self.m, b"r dco3 := dcs3\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "history test"):
            os.write(self.m, b"; test command\r\x1B[A\r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(; test command\r\n~?[\-#]){2}")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "line edit test"):
            os.write(self.m,
                b"r ax xyz\x08\x08\x08."
                + b"\x1B[D" * 4
                + b"e\r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"\r\nEAX +[0-9A-Fa-f]{8}\r\n")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "sleep test"):
            self.do_write_long("""
                r v0 := dword [$40:6C]
                sleep 1 ticks
                h v0 == dword [$40:6C]
                """)
            self.do_read(sleepduration = 0.2)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"\r\n0+  decimal")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "paging test"):
            self.do_write_long("""
                r v0 := dsr
                r dsr := 4
                d 100 l 10 * 6
                """)
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"d 100 l 10 \* 6(\r\n[0-9A-Fa-f:]{9,13}  ([0-9A-Fa-f]{2}[\- ]){16}.{16}){2}\r\n\[more\]$")
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b" ")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"^([0-9A-Fa-f:]{9,13}  ([0-9A-Fa-f]{2}[\- ]){16}.{16}\r\n){3}\[more\]$")
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b" ")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"^([0-9A-Fa-f:]{9,13}  ([0-9A-Fa-f]{2}[\- ]){16}.{16}\r\n){1}~?[\-#]$")
            self.assertNotRegex(self.buffer,
                r"\[more\]")
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"r dsr := v0\rh dsr\r")
            self.do_read()
            self.assertNotIn("^ Error", self.buffer)
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "compare test"):
            self.do_write_long("""
                f 100 l 8 90
                e 200 90 90 90 90 0 1 2 3
                c 100 l 8 200
                """)
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertEqual(4, len(re.findall(
                r"[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2} +[0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n", self.buffer)))
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "t/tp/p test"):
            self.do_write_long("""
                a 100
                 mov cx, 8
                 .
                r v0 = aao
                a
                 loop (v0)
                 mov cx, 8
                 mov si, 100
                 rep lodsb
                 nop
                 int3
                 jmp 100
                 .
                t=100
                """)
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +loop ")
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"t\r")
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +loop ")
            self.assertEqual(1, len(re.findall(
                r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"tp\r")
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +loop ")
            self.assertEqual(1, len(re.findall(
                r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"p\rp\rp\r")
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +loop ")
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +mov +cx")
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +mov +si")
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +rep +lodsb")
            self.assertEqual(3, len(re.findall(
                r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"t\r")
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +rep +lodsb")
            self.assertEqual(1, len(re.findall(
                r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
            if self.debug:
                print(self.buffer)
            self.buffer = ""
            os.write(self.m, b"tp\r")
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?i)\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} +nop")
            self.assertEqual(1, len(re.findall(
                r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "ff longer test"):
            self.do_write_long("""
                f 200 l 10 0
                f 200 l 8  1 2 3 4 5 6 7 8 9
                e 300  1 2 3 4 5 6 7 8, 0 0 0 0, 0 0 0 0
                c 200 l 10  300
                """)
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertEqual(0, len(re.findall(
                r"[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2} +[0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n", self.buffer)))
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "ff range test"):
            self.do_write_long("""
                f 400 l 10 0
                f 208 l 8 90
                f 400 l 8  range 200 l 10
                c 300 l 10  400
                """)
            self.do_read(sleepduration = 0.1)
            self.assertNotIn("^ Error", self.buffer)
            self.assertEqual(0, len(re.findall(
                r"[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2} +[0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n", self.buffer)))
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "ss range test"):
            self.do_write_long("""
                s 400 l 10  range 300 l 10
                """)
            self.do_read(sleepduration = 0.2)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer, r"\r\n0*1 match(es)?\r\n")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "ss range fail test"):
            self.do_write_long("""
                s 400 l 10  range 300 l 11
                """)
            self.do_read(sleepduration = 0.2)
            self.assertIn("^ Error", self.buffer)
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        with self.subtestcontext(msg = "ss list fail test"):
            self.do_write_long("""
                s 400 l 10  0 1 2 3, 4 5 6 7, 8 9 A B, C D E F, 10
                """)
            self.do_read(sleepduration = 0.2)
            self.assertIn("^ Error", self.buffer)
        if self.debug:
            print(self.buffer)

    @unittest.expectedFailure
    def test_timeout(self):
        time.sleep(0.05)
        os.write(self.m, b"sleep #10 seconds\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")

    @unittest.skipIf(booting, "test is non-booting only")
    def test_int2D_unhook(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"r tryamisnum := 26\rr dco4 or= 8\rh dco4 and 8\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\n0*8  decimal:")
        self.buffer = ""
        os.write(self.m, b"h amisnum\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\n0*26  decimal:")
        self.buffer = ""
        os.write(self.m, b"r amisnum 0\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\nThis lDebug variable cannot be written to.")
        self.buffer = ""
        os.write(self.m, b"di 2D\rr dpr .\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        p = re.compile(r"\r\nDPR ([0-9A-Fa-f]{4})\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        debuggerentrysegment = m.group(1)
        self.assertTrue(debuggerentrysegment is not None)
        self.assertRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggerentrysegment)
        self.buffer = ""
        self.do_write_long("""
            a 100
             mov ax, 352D
             int 21
             mov ah, 25
             mov word [200], EA90
             mov word [202], bx
             mov word [204], es
             mov word [206], cx
             mov dx, 200
             int 21
             int3
             nop
             .
            r v0 := aao
            a
             push ds
             lds dx, [202]
             mov ax, 252D
             int 21
             pop ds
             int3
             nop
             .
            r cx 0
            g=100
            r dco4 and= ~ 8
            di 2D
            """, sleepduration=0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        p = re.compile(r"CS=([0-9A-Fa-f]{4})")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        debuggeecodesegment = m.group(1)
        self.assertTrue(debuggeecodesegment is not None)
        self.assertRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggeecodesegment)
        self.buffer = ""
        self.do_write_long("""
            g=v0
            r dco4 or= 8
            di 2D
            r dco4 and= ~8
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggerentrysegment)
        self.buffer = ""
        os.write(self.m, b"di 2D\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggerentrysegment)
        self.assertNotRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggeecodesegment)
        self.buffer = ""
        self.do_write_long("""
            r dco4 or= 8
            r cx := #"KB"
            g=100
            r dco4 and= ~8
            di 2D
            h base=10 width=4 word [204]
            """, sleepduration=0.1)
        self.do_read(sleepduration = 0.5)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggerentrysegment)
        self.assertRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggeecodesegment)
        self.assertNotRegex(self.buffer,
            r"\r\n%s\r\n" % debuggerentrysegment)
        self.buffer = ""
        os.write(self.m, b"g=v0\rdi 2D\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggerentrysegment)
        self.assertNotRegex(self.buffer,
            r"\r\nint 2D %s:[0-9A-Fa-f]{4}( \(.*\))?\r\n" % debuggeecodesegment)

    def test_bb_gg(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        self.do_write_long("""
            a 100
             inc ax
             inc bx
             inc cx
             inc dx
             int3
             jmp 100
             .
            bp at 101 counter=4008 when= 1 == 1 id = inc bx
            bp at 102 when= 1 == 1 id = inc cx
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"bl\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n"
            + r"BP 00 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0101"
            + r" \(CC\) Counter=4008, ID: inc bx\r\n"
            + r" WHEN 1 == 1\r\n"
            + r"BP 01 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0102"
            + r" \(CC\) Counter=8000, ID: inc cx\r\n"
            + r" WHEN 1 == 1\r\n"
            )
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("\r\nPassed permanent breakpoint 00,"
            + " counter=4007, ID: inc bx\r\n",
            self.buffer);
        self.assertIn("\r\nHit permanent breakpoint 01, ID: inc cx\r\n",
            self.buffer);
        self.assertRegex(self.buffer, r"(?s)\r\n[0-9A-Fa-f]{4}:(0000)?0101 "
            + r".*\r\n[0-9A-Fa-f]{4}:(0000)?0102 ")
        self.assertEqual(2, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.assertEqual(2, len(re.findall(
            r"permanent breakpoint", self.buffer)))
        self.assertEqual(0, len(re.findall(
            r"Unexpected breakpoint interrupt", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"g\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(1, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.assertEqual(0, len(re.findall(
            r"permanent breakpoint", self.buffer)))
        self.assertEqual(1, len(re.findall(
            r"Unexpected breakpoint interrupt", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"g 100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(1, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.assertEqual(0, len(re.findall(
            r"permanent breakpoint", self.buffer)))
        self.assertEqual(0, len(re.findall(
            r"Unexpected breakpoint interrupt", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"g 100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("\r\nPassed permanent breakpoint 00,"
            + " counter=4006, ID: inc bx\r\n",
            self.buffer);
        self.assertIn("\r\nHit permanent breakpoint 01, ID: inc cx\r\n",
            self.buffer);
        self.assertRegex(self.buffer, r"(?s)\r\n[0-9A-Fa-f]{4}:(0000)?0101 "
            + r".*\r\n[0-9A-Fa-f]{4}:(0000)?0102 ")
        self.assertEqual(2, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.assertEqual(2, len(re.findall(
            r"permanent breakpoint", self.buffer)))
        self.assertEqual(0, len(re.findall(
            r"Unexpected breakpoint interrupt", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"ttest =100 ffff silent 2\r")
        time.sleep(0.20)
        os.write(self.m, b"\x03")
        self.do_read(sleepduration = 0.20)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"[^\-#]\^C\r\n")
        self.assertEqual(2, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"bc all\rbp at 101 when=0\rt=100\rbl\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(1, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.assertRegex(self.buffer,
            r"\r\n"
            + r"BP 00 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0101"
            + r" \(CC\) Counter=8000\r\n"
            + r" WHEN 0\r\n"
            )
        self.buffer = ""
        self.do_write_long(r"""
            re.append @r v0 -:= 1
            re.append @if (v0) then goto :eof
            re.append @r dco2 or= 8000   \; cancel tpg run
            re.list
            r v0 := 2
            t=100 4 silent 1
            """, sleepmodulo=2)
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(1, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"bl 0F\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n"
            + r"BP 0F Unused\r\n"
            )
        self.assertNotRegex(self.buffer, r" WHEN ")
        self.buffer = ""
        osizecondition = ""
        opcodeoffset = ""
        if self.dpmisubtest:
            osizecondition = "(byte [cs:ip] == 66) && "
            opcodeoffset = " + 1"
        self.do_write_long("""
            bd all
            re.replace @R
            r ip 100
            t 10 while %s(value byte [cs:ip%s] in from 40 to 4F)
            """ % (osizecondition, opcodeoffset), sleepmodulo=2)
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(4, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.assertRegex(self.buffer,
            r'\r\nWhile condition ".*" no longer true.\r\n')
        self.buffer = ""
        self.do_write_long("""
            bw 0
            bp at 102
            bp at 103
            bl all
            """, sleepmodulo=2)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(3, len(re.findall(
            r"\r\nBP [0-9A-Fa-f]{2} [\-+] ", self.buffer)))
        self.assertRegex(self.buffer,
            r'\r\nBP 00 - .*\r\nBP 01 \+ .*\r\nBP 02 \+ ')
        self.buffer = ""
        os.write(self.m, b"bt all\rbl all\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(3, len(re.findall(
            r"\r\nBP [0-9A-Fa-f]{2} [\-+] ", self.buffer)))
        self.assertRegex(self.buffer,
            r'\r\nBP 00 \+ .*\r\nBP 01 - .*\r\nBP 02 - ')
        self.buffer = ""
        os.write(self.m, b"be 02\rbl all\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(3, len(re.findall(
            r"\r\nBP [0-9A-Fa-f]{2} [\-+] ", self.buffer)))
        self.assertRegex(self.buffer,
            r'\r\nBP 00 \+ .*\r\nBP 01 - .*\r\nBP 02 \+ ')
        self.buffer = ""
        os.write(self.m, b"bc all\rbl all\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(0, len(re.findall(
            r"\r\nBP [0-9A-Fa-f]{2} [\-+] ", self.buffer)))
        self.assertRegex(self.buffer,
            r'\r\nNo breakpoints set currently.\r\n')
        self.buffer = ""
        os.write(self.m, b"g=100 100 102\rg list\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(2, len(re.findall(
            r"\r\n *[0-9]+(th|st|nd|rd) +G breakpoint", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"g=100 again 103\rg list\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(3, len(re.findall(
            r"\r\n *[0-9]+(th|st|nd|rd) +G breakpoint", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"g again 104 remember\rg list\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(4, len(re.findall(
            r"\r\n *[0-9]+(th|st|nd|rd) +G breakpoint", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"g remember\rg list\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r'\r\nThe G breakpoint list is empty.\r\n')
        self.buffer = ""
        os.write(self.m, b"re.replace @R; @sleep 1 ticks\rt=100 4 silent 2\r")
        self.do_read(sleepduration = 0.01, noaddsleep = True)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(0, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        self.do_read(sleepduration = 1.0 / 18.2 * 4.0)
        if self.debug:
            print(self.buffer)
        self.assertEqual(2, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} [0-9A-Fa-f]{2,} ", self.buffer)))

    def test_bb_fill(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        self.do_write_long("""
            bp at 100 when ax id accumulator
            bp at 200 when = cx id = counter
            bp at 300 when =   dx   id = data
            bp at 400 counter=4008 when bx id base
            """, sleepduration = 0.1, sleepmodulo = 3)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"bl\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n"
            + r"BP 00 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0100"
            + r" \(CC\) Counter=8000, ID: accumulator\r\n"
            + r" WHEN ax\r\n"
            + r"BP 01 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0200"
            + r" \(CC\) Counter=8000, ID: counter\r\n"
            + r" WHEN cx\r\n"
            + r"BP 02 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0300"
            + r" \(CC\) Counter=8000, ID: data\r\n"
            + r" WHEN dx\r\n"
            + r"BP 03 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0400"
            + r" \(CC\) Counter=4008, ID: base\r\n"
            + r" WHEN bx\r\n"
            + r"~?[-#]$"
            )
        self.buffer = ""
        os.write(self.m, b"bc 2\rbl\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n"
            + r"BP 00 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0100"
            + r" \(CC\) Counter=8000, ID: accumulator\r\n"
            + r" WHEN ax\r\n"
            + r"BP 01 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0200"
            + r" \(CC\) Counter=8000, ID: counter\r\n"
            + r" WHEN cx\r\n"
            + r"BP 03 \+ Lin=[_0-9A-Fa-f]+  ([0-9A-Fa-f]{4}|CS):0400"
            + r" \(CC\) Counter=4008, ID: base\r\n"
            + r" WHEN bx\r\n"
            + r"~?[-#]$"
            )
        self.buffer = ""
        os.write(self.m, b"bc all\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        found = 0
        for x in range(0, 256 + 4):
            self.buffer = ""
            os.write(self.m, ("bp at %04X\r" % x).encode())
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            if "\r\nNo unused breakpoint left!\r\n" in self.buffer:
                found = 1
                amount = x
                break
        self.assertTrue(found)
        self.buffer = ""
        os.write(self.m, b"bc all\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        found = 0
        for x in range(0, amount - 1):
            self.buffer = ""
            os.write(self.m, ("bp at %04X id = %s\r" % (x, 20 * "ID")).encode())
            self.do_read(sleepduration = 0.1)
            if self.debug:
                print(self.buffer)
            length = len("-bp at 0000 id = ")
            pattern = re.compile(r"\r\n {%u,%u}\^ Error" % (length - 2, length + 2))
            if re.search(pattern, self.buffer):
                found = 1
                break
            self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, pattern)
        self.assertTrue(found)
        self.buffer = ""
        os.write(self.m, b"bc all\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        found = 0
        for x in range(0, amount - 1):
            self.buffer = ""
            os.write(self.m, ("bp at %04X when = %s\r"
                % (x, (20 * "1 == ") + "1")).encode())
            self.do_read(sleepduration = 0.3)
            if self.debug:
                print(self.buffer)
            length = len("-bp at 0000 when = ")
            pattern = re.compile(r"\r\n {%u,%u}\^ Error" % (length - 2, length + 2))
            if re.search(pattern, self.buffer):
                found = 1
                break
            self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, pattern)
        self.assertTrue(found)
        self.buffer = ""
        os.write(self.m, b"bc all\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = 1234_5678\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        length = len("-bp at 0000 number = 1234_5678")
        pattern = re.compile(r"\r\n {%u,%u}\^ Error" % (length - 2, length + 2))
        self.assertRegex(self.buffer, pattern)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = -1\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = FFFF_FFFF\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        length = len("-bp at 0000 number = FFFF_FFFF")
        pattern = re.compile(r"\r\n {%u,%u}\^ Error" % (length - 2, length + 2))
        self.assertRegex(self.buffer, pattern)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = sdword 8000\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        length = len("-bp at 0000 number = sdword 8000")
        pattern = re.compile(r"\r\n {%u,%u}\^ Error" % (length - 2, length + 2))
        self.assertRegex(self.buffer, pattern)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = sdword FFFF\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        length = len("-bp at 0000 number = sdword FFFF")
        pattern = re.compile(r"\r\n {%u,%u}\^ Error" % (length - 2, length + 2))
        self.assertRegex(self.buffer, pattern)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = 1_0000\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        length = len("-bp at 0000 number = 1_0000")
        pattern = re.compile(r"\r\n {%u,%u}\^ Error" % (length - 2, length + 2))
        self.assertRegex(self.buffer, pattern)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = -8001\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        length = len("-bp at 0000 number = -8001")
        pattern = re.compile(r"\r\n {%u,%u}\^ Error" % (length - 2, length + 2))
        self.assertRegex(self.buffer, pattern)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = -8000\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = -7FFF\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = sdword 7FFF\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"bp at 0000 number = FFFF\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)

    def test_access_var(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"r readadr0 .\rr readlen0 .\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        if "^ Error" in self.buffer:
            raise unittest.SkipTest("build does not include access variables")
        sleepduration = 0.05
        sleepmodulo = 4
        self.buffer = ""
        self.do_write_long("""
            a 100
             mov ax, 40
             mov es, ax
             mov bx, 6C
             int3
             mov dx, word [es:bx]
             int3
             add word [es:bx], 0
             int3
             mov word [200], dx
             int3
             push word [200]
             int3
             pop word [200]
             int3
             jmp 100
             .
            r ip 100
            """, sleepduration = sleepduration, sleepmodulo = sleepmodulo)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        self.do_write_long("""
            g   ; up to mov dx
            r readadr0 .
            r readlen0 .
            r readadr1 .
            r readlen1 .
            r writadr0 .
            r writlen0 .
            dl es
            """, sleepduration = sleepduration, sleepmodulo = sleepmodulo)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"(?i) mov +dx")
        if not (machine == 'qemu' and self.dpmisubtest):
            self.assertRegex(self.buffer, r"\r\nREADADR0 0*46C\r\n")
            self.assertRegex(self.buffer, r"\r\nREADLEN0 0*2\r\n")
        else:
            self.assertRegex(self.buffer, r"\r\n0040 base=\?{8} ")
        self.assertRegex(self.buffer, r"\r\nREADADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nREADLEN1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITADR0 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITLEN0 0*0\r\n")
        self.buffer = ""
        self.do_write_long("""
            g   ; up to add
            r readadr0 .
            r readlen0 .
            r readadr1 .
            r readlen1 .
            r writadr0 .
            r writlen0 .
            r writadr1 .
            r writlen1 .
            dl es
            """, sleepduration = sleepduration, sleepmodulo = sleepmodulo)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"(?i) add +word")
        if not (machine == 'qemu' and self.dpmisubtest):
            self.assertRegex(self.buffer, r"\r\nREADADR0 0*46C\r\n")
            self.assertRegex(self.buffer, r"\r\nREADLEN0 0*2\r\n")
        else:
            self.assertRegex(self.buffer, r"\r\n0040 base=\?{8} ")
        self.assertRegex(self.buffer, r"\r\nREADADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nREADLEN1 0*0\r\n")
        if not (machine == 'qemu' and self.dpmisubtest):
            self.assertRegex(self.buffer, r"\r\nWRITADR0 0*46C\r\n")
            self.assertRegex(self.buffer, r"\r\nWRITLEN0 0*2\r\n")
        else:
            self.assertRegex(self.buffer, r"\r\n0040 base=\?{8} ")
        self.assertRegex(self.buffer, r"\r\nWRITADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITLEN1 0*0\r\n")
        self.buffer = ""
        self.do_write_long("""
            g   ; up to mov
            r readadr0 .
            r readlen0 .
            r writadr0 .
            r writlen0 .
            r writadr1 .
            r writlen1 .
            h linear ds:200
            """, sleepduration = sleepduration, sleepmodulo = sleepmodulo)
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"(?i) mov.*\[")
        p = re.compile(r"\r\n0*([1-9A-Fa-f][0-9A-Fa-f]*)  decimal:.*\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        debuggeedatalinear = m.group(1)
        self.assertTrue(debuggeedatalinear is not None)
        self.assertRegex(self.buffer, r"\r\nREADADR0 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nREADLEN0 0*0\r\n")
        self.assertRegex(self.buffer,
            r"\r\nWRITADR0 0*%s\r\n" % debuggeedatalinear)
        self.assertRegex(self.buffer, r"\r\nWRITLEN0 0*2\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITLEN1 0*0\r\n")
        self.buffer = ""
        self.do_write_long("""
            g   ; up to push
            r readadr0 .
            r readlen0 .
            r readadr1 .
            r readlen1 .
            r writadr0 .
            r writlen0 .
            r writadr1 .
            r writlen1 .
            h linear ss:sp - 2
            """, sleepduration = sleepduration, sleepmodulo = sleepmodulo)
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"(?i) push.*\[")
        p = re.compile(r"\r\n0*([1-9A-Fa-f][0-9A-Fa-f]*)  decimal:.*\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        debuggeestacklinear = m.group(1)
        self.assertTrue(debuggeestacklinear is not None)
        self.assertRegex(self.buffer,
            r"\r\nREADADR0 0*%s\r\n" % debuggeedatalinear)
        self.assertRegex(self.buffer, r"\r\nREADLEN0 0*2\r\n")
        self.assertRegex(self.buffer, r"\r\nREADADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nREADLEN1 0*0\r\n")
        self.assertRegex(self.buffer,
            r"\r\nWRITADR0 0*%s\r\n" % debuggeestacklinear)
        self.assertRegex(self.buffer, r"\r\nWRITLEN0 0*2\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITLEN1 0*0\r\n")
        self.buffer = ""
        self.do_write_long("""
            g   ; up to pop
            r readadr0 .
            r readlen0 .
            r readadr1 .
            r readlen1 .
            r writadr0 .
            r writlen0 .
            r writadr1 .
            r writlen1 .
            """, sleepduration = sleepduration, sleepmodulo = sleepmodulo)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"(?i) pop.*\[")
        self.assertTrue(debuggeestacklinear is not None)
        self.assertRegex(self.buffer,
            r"\r\nREADADR0 0*%s\r\n" % debuggeestacklinear)
        self.assertRegex(self.buffer, r"\r\nREADLEN0 0*2\r\n")
        self.assertRegex(self.buffer, r"\r\nREADADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nREADLEN1 0*0\r\n")
        self.assertRegex(self.buffer,
            r"\r\nWRITADR0 0*%s\r\n" % debuggeedatalinear)
        self.assertRegex(self.buffer, r"\r\nWRITLEN0 0*2\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITLEN1 0*0\r\n")
        self.buffer = ""
        self.do_write_long("""
            g   ; up to jmp
            r readadr0 .
            r readlen0 .
            r readadr1 .
            r readlen1 .
            r writadr0 .
            r writlen0 .
            r writadr1 .
            r writlen1 .
            """, sleepduration = sleepduration, sleepmodulo = sleepmodulo)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"(?i) jmp ")
        self.assertRegex(self.buffer, r"\r\nREADADR0 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nREADLEN0 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nREADADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nREADLEN1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITADR0 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITLEN0 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITADR1 0*0\r\n")
        self.assertRegex(self.buffer, r"\r\nWRITLEN1 0*0\r\n")

    @unittest.skipIf(booting, "test is non-booting only")
    @unittest.skipIf("x" not in build_name, "build does not include dpmi")
    @unittest.skipIf(not dpmiavailable, "dpmi not available")
    def test_dpmimini(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"r dps .\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        if "^ Error" in self.buffer:
            raise unittest.SkipTest("build does not include dpmi")
        sleepduration = 0.05
        sleepmodulo = 4
        self.buffer = ""
        if self.dpmiexe is not None:
            self.do_write_long("""
                n %s
                l
                g
                """ % self.dpmiexe)
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotIn("File not found", self.buffer)
            self.assertNotIn("Path not found", self.buffer)
            self.assertNotIn("Access denied", self.buffer)
            self.assertNotIn("Insufficient memory", self.buffer)
            self.assertNotRegex(self.buffer, r"Error .* opening file")
            self.buffer = ""
        self.do_write_long("""
            n %sdpmimini.com
            l
            s 100 l bxcx "Protected mode breakpoint at "
            """ % self.dpmidir, sleepmodulo = 2, sleepduration = 0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("File not found", self.buffer)
        self.assertNotIn("Path not found", self.buffer)
        self.assertNotIn("Access denied", self.buffer)
        self.assertNotIn("Insufficient memory", self.buffer)
        self.assertNotRegex(self.buffer, r"Error .* opening file")
        self.assertIn("DPMI entry hooked", self.buffer)
        p = re.compile(r"\r\n[0-9A-Fa-f:]{9}(?: \+[0-9A-Fa-f]{2,8})?  "
            + r"([0-9A-Fa-f]{2}[- ]){16}([0-9A-Fa-f]{4})h"
            + r".*\r\n0001 matches\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        breakpoint = m.group(2)
        self.assertTrue(breakpoint is not None)
        self.buffer = ""
        self.do_write_long("""
            g
            g %s
            """ % breakpoint)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"[\r\n]~?#$")
        self.buffer = ""
        os.write(self.m, b"rvm\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        p = re.compile(r"\r\nEntry segment=[0-9A-Fa-f]{4} "
            + r"selector=([0-9A-Fa-f]{4})\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        debuggerentryselector = m.group(1)
        self.assertTrue(debuggerentryselector is not None)
        p = re.compile(r"\r\nData segment=[0-9A-Fa-f]{4} "
            + r"selector=([0-9A-Fa-f]{4})\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        debuggerdataselector = m.group(1)
        self.assertTrue(debuggerdataselector is not None)
        self.buffer = ""
        if "ddebug" not in build_name:
            # Note: Can fail in dosemu2 prior to our hg b2212e4d65fb.
            #  Does not appear to fail in qemu.
            #
            # Skipped for ddebugx because the GPF would go to the
            #  default system handler instead of our debugger's,
            self.buffer = ""
            os.write(self.m, ("dl %s\r" % debuggerdataselector).encode())
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"limit=0+[Ff]{4}\b")
            self.buffer = ""
            os.write(self.m, b"r dword [cs:A0] := FFFF_FFFF\r")
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotIn("General protection fault", self.buffer)
        os.write(self.m, b"di 0\rdi 1\rdi 3\rdi 6\rdi 0C\rdi 0D\rdi 0E\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\nint [0-9A-Fa-f]{2}( +[0-9A-Fa-f:]{9,13}){2}\r\n")
        if "ddebug" not in build_name:
            self.assertEqual(7, len(re.findall(
                r"\r\nint [0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13} +%s:[0-9A-Fa-f]{4,8}\r\n" % debuggerentryselector, self.buffer)))
        else:
            self.assertEqual(7, len(re.findall(
                r"\r\nint [0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f:]{9,13}\r\n", self.buffer)))
        self.assertNotRegex(self.buffer,
            r"\r\nint [0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n")
        self.buffer = ""
        os.write(self.m, b"di 21\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nint [0-9A-Fa-f]{2}( +[0-9A-Fa-f:]{9,13}){2}\r\n")
        self.assertRegex(self.buffer,
            r"\r\nint [0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n")
        if "ddebug" not in build_name:
            self.assertEqual(1, len(re.findall(
                r"\r\nint [0-9A-Fa-f]{2} +%s:[0-9A-Fa-f]{4,8}\r\n" % debuggerentryselector, self.buffer)))
        else:
            self.assertEqual(1, len(re.findall(
                r"\r\nint [0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n", self.buffer)))
        self.buffer = ""
        miscpmtests = [
            ("psp var", "h segment ppi == dpr || dif & 4000", "\r\n0*1  decimal:"),
            ("psp var", "h ppr == dpr || dif & 4000", "\r\n0*1  decimal:"),
            ("psp var", "h psp != 0 || dif & 4000", "\r\n0*1  decimal:"),
            ("psp var", "h (linear psps:0) == (psp << 4) || dif & 4000", "\r\n0*1  decimal:", 1, 1),
            ]
        for tuple in miscpmtests:
            msg = tuple[0]
            cmd = tuple[1]
            match = tuple[2]
            if len(tuple) >= 4:
                success = tuple[3]
            else:
                success = 1
            if len(tuple) >= 5:
                delay = tuple[4]
            else:
                delay = 0
            with self.subtestcontext(msg = msg + ": " + cmd.replace("\r","##")):
                if self.debug:
                    print(self.buffer)
                    print("msg=%s cmd=%s match=%s success=%d"
                        % (msg, cmd.replace("\r","##"),
                            match.replace("\r","##").replace("\n","%%"),
                            success))
                self.buffer = ""
                actuallysucceeded = 0
                try:
                    os.write(self.m, ("%s\r" % cmd).encode())
                    if delay:
                        time.sleep(0.05)
                    self.do_read()
                    self.assertNotRegex(self.buffer,
                        r"\^ Error",
                        "error in command")
                    self.assertRegex(self.buffer,
                        match,
                        "match mismatch")
                    actuallysucceeded = 1
                except AssertionError as e:
                    if success:
                        raise e
                    else:
                        if self.debug:
                            print("passing on upon AssertionError(\""
                                + str(e) + "\")")
                        pass
                if actuallysucceeded and not success:
                    raise AssertionError("unexpected success")
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"g\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("Program terminated normally", self.buffer)
        self.assertRegex(self.buffer, r"[\r\n]~?-$")

    @unittest.skipIf(booting, "test is non-booting only")
    @unittest.skipIf("x" not in build_name, "build does not include dpmi")
    @unittest.skipIf(not dpmiavailable, "dpmi not available")
    def test_dpmioffs(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"r dps .\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        if "^ Error" in self.buffer:
            raise unittest.SkipTest("build does not include dpmi")
        sleepduration = 0.05
        sleepmodulo = 4
        self.buffer = ""
        if self.dpmiexe is not None:
            self.do_write_long("""
                n %s
                l
                g
                """ % self.dpmiexe)
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotIn("File not found", self.buffer)
            self.assertNotIn("Path not found", self.buffer)
            self.assertNotIn("Access denied", self.buffer)
            self.assertNotIn("Insufficient memory", self.buffer)
            self.assertNotRegex(self.buffer, r"Error .* opening file")
            self.buffer = ""
        self.do_write_long("""
            n %sdpmioffs.com
            l
            s 100 l bxcx "32-bit es / 16-bit ds breakpoint at "
            """ % self.dpmidir, sleepmodulo = 2, sleepduration = 0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("File not found", self.buffer)
        self.assertNotIn("Path not found", self.buffer)
        self.assertNotIn("Access denied", self.buffer)
        self.assertNotIn("Insufficient memory", self.buffer)
        self.assertNotRegex(self.buffer, r"Error .* opening file")
        self.assertIn("DPMI entry hooked", self.buffer)
        p = re.compile(r"\r\n[0-9A-Fa-f:]{9}(?: \+[0-9A-Fa-f]{2,8})?  "
            + r"([0-9A-Fa-f]{2}[- ]){16}([0-9A-Fa-f]{4})h"
            + r".*\r\n0001 matches\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        ds16breakpoint = m.group(2)
        self.assertTrue(ds16breakpoint is not None)
        self.buffer = ""
        self.do_write_long("""
            s 100 l bxcx "32-bit ds / 16-bit es breakpoint at "
            """, sleepmodulo = 2, sleepduration = 0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        p = re.compile(r"\r\n[0-9A-Fa-f:]{9}(?: \+[0-9A-Fa-f]{2,8})?  "
            + r"([0-9A-Fa-f]{2}[- ]){16}([0-9A-Fa-f]{4})h"
            + r".*\r\n0001 matches\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        ds32breakpoint = m.group(2)
        self.assertTrue(ds32breakpoint is not None)
        self.buffer = ""
        self.do_write_long("""
            g
            g %s
            """ % ds16breakpoint)
        self.do_read(sleepduration = 0.5)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Program terminated normally", self.buffer)
        self.assertRegex(self.buffer, r"[\r\n]~?#$")
        self.buffer = ""
        os.write(self.m, b"c es:edi l 1 es:edi + 1\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n[0-9A-Fa-f]{4}:000[0-9A-Fa-f]{4}0 +00 +"
            + r"01 +[0-9A-Fa-f]{4}:000[0-9A-Fa-f]{4}1\r\n")
        self.buffer = ""
        os.write(self.m, b"c ds:0 l 1 ds:0 + 1\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n[0-9A-Fa-f]{4}:0000 +00 +"
            + r"01 +[0-9A-Fa-f]{4}:0001\r\n")
        self.buffer = ""
        self.do_write_long("""
            g %s
            """ % ds32breakpoint)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Program terminated normally", self.buffer)
        self.buffer = ""
        os.write(self.m, b"c ds:edi l 1 ds:edi + 1\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n[0-9A-Fa-f]{4}:000[0-9A-Fa-f]{4}0 +00 +"
            + r"01 +[0-9A-Fa-f]{4}:000[0-9A-Fa-f]{4}1\r\n")
        self.buffer = ""
        os.write(self.m, b"c es:0 l 1 es:0 + 1\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n[0-9A-Fa-f]{4}:0000 +00 +"
            + r"01 +[0-9A-Fa-f]{4}:0001\r\n")
        self.buffer = ""
        os.write(self.m, b"c es:(dword [ds:1_0000] & 0) l 1 es:0 + 1\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n[0-9A-Fa-f]{4}:0000 +00 +"
            + r"01 +[0-9A-Fa-f]{4}:0001\r\n")
        self.buffer = ""
        os.write(self.m, b"c es:(linear ds:1_0000, & 0) l 1 es:0 + 1\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n[0-9A-Fa-f]{4}:0000 +00 +"
            + r"01 +[0-9A-Fa-f]{4}:0001\r\n")
        self.buffer = ""
        os.write(self.m, b"g\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("Program terminated normally", self.buffer)
        self.assertRegex(self.buffer, r"[\r\n]~?-$")

    @unittest.skipIf(booting, "test is non-booting only")
    @unittest.skipIf("x" not in build_name, "build does not include dpmi")
    @unittest.skipIf(not dpmiavailable, "dpmi not available")
    def test_dpmialoc(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"r dps .\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        if "^ Error" in self.buffer:
            raise unittest.SkipTest("build does not include dpmi")
        sleepduration = 0.05
        sleepmodulo = 4
        self.buffer = ""
        if self.dpmiexe is not None:
            self.do_write_long("""
                n %s
                l
                g
                """ % self.dpmiexe)
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotIn("File not found", self.buffer)
            self.assertNotIn("Path not found", self.buffer)
            self.assertNotIn("Access denied", self.buffer)
            self.assertNotIn("Insufficient memory", self.buffer)
            self.assertNotRegex(self.buffer, r"Error .* opening file")
            self.buffer = ""
        self.do_write_long("""
            n %sdpmialoc.com
            l
            """ % self.dpmidir, sleepmodulo = 2, sleepduration = 0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("File not found", self.buffer)
        self.assertNotIn("Path not found", self.buffer)
        self.assertNotIn("Access denied", self.buffer)
        self.assertNotIn("Insufficient memory", self.buffer)
        self.assertNotRegex(self.buffer, r"Error .* opening file")
        self.assertIn("DPMI entry hooked", self.buffer)
        self.buffer = ""
        os.write(self.m, b"r cs .\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        p = re.compile(r"\r\nCS\s+([0-9A-Fa-f]{4})\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        cs = m.group(1)
        self.assertTrue(cs is not None)
        self.buffer = ""
        self.do_write_long("""
            g
            g
            """)
        self.do_read(sleepduration = 0.5)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Program terminated normally", self.buffer)
        self.assertRegex(self.buffer, r"[\r\n]~?#$")
        self.assertRegex(self.buffer,
            r"\r\n[0-9A-Fa-f:]{13}\s+[0-9A-Fa-f]+\s+push\s+ebx\r\n")
        self.buffer = ""
        os.write(self.m, b"bp at bx:0\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"g\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\nHit permanent breakpoint 00\r\n")
        self.assertRegex(self.buffer, r"[\r\n]~?#$")
        self.buffer = ""
        os.write(self.m, b"g\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"[\r\n]~?-$")
        self.assertRegex(self.buffer,
            r"\r\n%s:[0-9A-Fa-f]{4}\s+" % cs)
        self.buffer = ""
        self.do_write_long("""
            a cs:A0
             int 12
             nop
             nop
             int3
             jmp (ip)
             .
            r ip A0
            r
            """)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"t\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Internal error in disassembler!", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n%s:00A2\s+90\s+nop\r\n" % cs)
        self.assertNotRegex(self.buffer,
            r"\r\n%s:[0-9A-Fa-f]{4}\s+CD12\s+int\s+12\r\n" % cs)

    @unittest.skipIf(booting, "test is non-booting only")
    def test_missing_executable(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        self.do_write_long("""
            n nonexist.$$$
            l
            """, sleepmodulo = 2, sleepduration = 0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("File not found", self.buffer)
        self.assertNotIn("Path not found", self.buffer)
        self.assertNotIn("Access denied", self.buffer)
        self.assertNotIn("Insufficient memory", self.buffer)
        self.assertNotRegex(self.buffer, r"Error .* opening file")
        self.buffer = ""
        self.do_write_long("""
            n nonexist.$$$\\nonexist.$$$
            l
            """, sleepmodulo = 2, sleepduration = 0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("File not found", self.buffer)
        self.assertIn("Path not found", self.buffer)
        self.assertNotIn("Access denied", self.buffer)
        self.assertNotIn("Insufficient memory", self.buffer)
        self.assertNotRegex(self.buffer, r"Error .* opening file")

    @unittest.skipIf(booting, "test is non-booting only")
    def test_error_executable(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        self.do_write_long("""
            n scripts\\toolarge.exe
            l
            """, sleepmodulo = 2, sleepduration = 0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("File not found", self.buffer)
        self.assertNotIn("Path not found", self.buffer)
        self.assertNotIn("Access denied", self.buffer)
        self.assertIn("Insufficient memory", self.buffer)
        self.assertNotRegex(self.buffer, r"Error .* opening file")
        if machine == 'qemu':
            # dosemu's redirector apparently gives "File not found" for this
            self.buffer = ""
            self.do_write_long("""
                n scripts
                l
                """, sleepmodulo = 2, sleepduration = 0.1)
            self.do_read(sleepduration = 0.1)
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotIn("File not found", self.buffer)
            self.assertNotIn("Path not found", self.buffer)
            self.assertIn("Access denied", self.buffer)
            self.assertNotIn("Insufficient memory", self.buffer)
            self.assertNotRegex(self.buffer, r"Error .* opening file")

    @unittest.skipIf(not booting, "test is booting only")
    def test_load_boot(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m,
            ("boot protocol=ldos ldp/l%s.com\rr\r" % build_name).encode())
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertRegex(self.buffer, r"\r\n0200:0400 ")
        self.buffer = ""
        os.write(self.m,
            ("boot protocol=ldos checkvalue=FFFF ldp/l%s.com\r" % build_name).encode())
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("Boot failure: Check mismatch", self.buffer)
        self.buffer = ""
        os.write(self.m,
            ("boot protocol=rxdos.3\r").encode())
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("Boot failure: File not found", self.buffer)
        self.buffer = ""
        os.write(self.m,
            ("boot protocol=freedos ldp/l%s.com\rr\r" % build_name).encode())
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertRegex(self.buffer, r"\r\n0060:0000 ")
        self.buffer = ""
        os.write(self.m, b"boot dir ldp/\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertRegex(self.buffer, r"\r\nEXTLIB +ELD +[\-AHSR]{4} +[0-9]+")
        self.assertRegex(self.buffer, r"\r\nL[CD]?DEBUG +SLD +[\-AHSR]{4} +[0-9]+")
        self.buffer = ""
        os.write(self.m, b"boot read ldp 1000\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.buffer = ""
        os.write(self.m, b"s 1000:0 l 200 'FAT12   '\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertRegex(self.buffer, r"\r\n0001 match(es)?\r\n")
        self.buffer = ""
        os.write(self.m, b"d 1000:1F0 l 10\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n[0-9A-Fa-f:]{9,13}  ([0-9A-Fa-f]{2}[\- ]){14}55 AA .{16}\r\n")
        self.buffer = ""
        os.write(self.m, b"r byte [1000:400] = 0\r"
            + b"boot read ldp 1020\rc 1000:0 l 200 1000:200\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2} +[0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n")
        self.buffer = ""
        os.write(self.m, b"boot read ldp 1020 0\rc 1000:0 l 200 1000:200\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2} +[0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n")
        self.buffer = ""
        os.write(self.m, b"boot read ldp 1020 0 1\rc 1000:0 l 200 1000:200\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2} +[0-9A-Fa-f]{2} +[0-9A-Fa-f:]{9,13}\r\n")
        self.buffer = ""
        os.write(self.m, b"h byte [1000:400]\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\n0+ +decimal")

    def test_yy(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"y scripts/simple.sld\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; simple script content\r\n")
        self.buffer = ""
        os.write(self.m, b"y scripts/levels20.sld\r")
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertNotRegex(self.buffer, r"\r\nV0+=0+ ")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 20 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 19 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 18 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 18 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 19 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 20 end\r\n")
        self.buffer = ""
        os.write(self.m, b"y scripts/levels02.sld\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 start\r\n")
        self.assertRegex(self.buffer, r"\r\nV0+=0+ ")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 end\r\n")
        self.buffer = ""
        os.write(self.m, b"r v0 := 0\rr v1 := 0\rr v2 := 0\ry scripts/sleep02.sld\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 end\r\n")
        self.buffer = ""
        os.write(self.m, b"r v0 := #18\rr iol := 0\ry scripts/sleep02.sld\r")
        time.sleep(0.20)
        os.write(self.m, b"\x03")
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 end\r\n")
        self.buffer = ""
        os.write(self.m, b"r v0 := #18\rr iol := 1\ry scripts/sleep02.sld\r")
        time.sleep(0.20)
        os.write(self.m, b"\x03")
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 start\r\n")
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]; level 00 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 end\r\n")
        self.buffer = ""
        os.write(self.m, b"r v0 := #18\rr v1 := v0\rr iol := 1\ry scripts/sleep02.sld\r")
        time.sleep(0.20)
        os.write(self.m, b"\x03")
        time.sleep(0.20)
        os.write(self.m, b"\x03")
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 start\r\n")
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]; level 00 end\r\n")
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]; level 01 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 end\r\n")
        self.buffer = ""
        os.write(self.m, b"r iol := 2\ry scripts/sleep02.sld\r")
        time.sleep(0.20)
        os.write(self.m, b"\x03")
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 01 start\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 00 start\r\n")
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]; level 00 end\r\n")
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]; level 01 end\r\n")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]; level 02 end\r\n")
        self.buffer = ""
        os.write(self.m, b"y scripts/self.sld :entry\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertRegex(self.buffer,
            r"\r\n~?[\-#]; self entry"
            + r"\r\n~?[\-#]y :another"
            + r"\r\n~?[\-#]; another entry"
            + r"\r\n~?[\-#]y :yetanother"
            + r"\r\n~?[\-#]; yet another"
            + r"\r\n~?[\-#]goto :eof"
            + r"\r\n~?[\-#]; another exit"
            + r"\r\n~?[\-#]goto :eof"
            + r"\r\n~?[\-#]; self exit"
            )
        self.buffer = ""
        os.write(self.m, b"y scripts/hide.sld\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("Boot failure", self.buffer)
        self.assertNotRegex(self.buffer,
            r"\r\nY command has too many open files.\r\n"
            + r"|\r\nY command failed to open file.\r\n")
        self.assertRegex(self.buffer,
            r"\r\n~?[\-#]; visible 1"
            + r"\r\n~?[\-#]r ysf or= 4000"
            + r"\r\nAX [0-9A-Fa-f]{4}"
            + r"\r\n~?[\-#]; visible 2"
            )
        self.assertNotRegex(self.buffer, "invisible")

    def test_double_ctrlc(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        self.do_write_long("""
            f cs:100 l 100 90
            t=100  ; hook int2F in DebugX
            a 100
             mov cx, (#18 * 3)
             mov bx, 40
             mov es, bx
             .
            r v0 := aao
            a
             mov dx, word [es:6C]
             .
            r v1 := aao
            a
             cmp dx, word [es:6C]
             jne 140
             mov ax, 1680
             .
            r v2 := aao
            a
             int 2F
             test al, al
             jz (v1)
             sti
             hlt
             jmp (v1)
             ;
             org 140
             loop (v0)
             int3
             .
            r dco4 or= 4  ; hook interrupt 8
            r cs .
            """, sleepmodulo = 4)
        self.do_write_long("""
            if (ri2Fo == ffff || ri2Fs == 0) then r word [cs:v2] := 9090
            h word [cs:v2]
            """, sleepmodulo = 1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        p = re.compile(r"(?i)\r\nCS +([0-9A-Fa-f]{4})\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        codesegment = m.group(1)
        self.assertTrue(codesegment is not None)
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read(sleepduration = 0.1, noaddsleep = True)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, "g=100\r\n$")
        self.buffer = ""
        os.write(self.m, b"\x03\x03")
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, "^Detected double Control-C via serial\r\n")
        p = re.compile(r"\r\n([0-9A-Fa-f]{4}):([0-9A-Fa-f]{4}) +[0-9A-Fa-f]{2,} ")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        breaksegment = m.group(1)
        breakoffset = m.group(2)
        self.assertTrue(breaksegment is not None)
        self.assertTrue(breakoffset is not None)
        breakoffset = int("0x" + breakoffset, base=16)
        if breaksegment == codesegment:
            self.assertTrue(breakoffset >= 0x100 and breakoffset < 0x200)
        else:
            self.buffer = ""
            self.do_write_long("""
                r vf := 0
                re.replace @R
                re.append @r dco2 or= vf
                re.append @if (value byte [cs:eip] in CF, CA) then r vf := 8000
                tp ffff silent 1
                """, sleepmodulo = 2)
            self.do_read(sleepduration = 0.1)
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer, p)
            m = p.search(self.buffer)
            self.assertTrue(m is not None)
            breaksegment = m.group(1)
            breakoffset = m.group(2)
            self.assertTrue(breaksegment is not None)
            self.assertTrue(breakoffset is not None)
            breakoffset = int("0x" + breakoffset, base=16)
            self.assertTrue(breaksegment == codesegment)
            self.assertTrue(breakoffset >= 0x100 and breakoffset < 0x200)

    def test_eee_interactive(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"f 100 l 100 90\re 100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.assertRegex(self.buffer, r"\r\n[0-9A-Fa-f:]{9,13} +90\.$")
        self.buffer = ""
        os.write(self.m, b"26")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        os.write(self.m, b"\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        os.write(self.m, b"e 100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.assertRegex(self.buffer, r"\r\n[0-9A-Fa-f:]{9,13} +26\.$")
        self.buffer = ""
        os.write(self.m, b" ")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.assertRegex(self.buffer, r" +90\.$")
        self.buffer = ""
        os.write(self.m, b".")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        os.write(self.m, b"e 100\r  ")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.assertRegex(self.buffer, r"\r\n[0-9A-Fa-f:]{9,13} +26\. +90\. +90\.$")
        self.buffer = ""
        os.write(self.m, b"38")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        os.write(self.m, b"-")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.assertRegex(self.buffer, r"\r\n[0-9A-Fa-f:]{9,13} +90\.$")
        self.buffer = ""
        os.write(self.m, b" ")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.assertRegex(self.buffer, r" +38\.$")
        self.buffer = ""
        os.write(self.m, b"\n")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        os.write(self.m, b"e 107\r ")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.assertRegex(self.buffer, r"(\r\n[0-9A-Fa-f:]{9,13} +90\.){2}$")
        self.buffer = ""
        os.write(self.m, b"\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        os.write(self.m, b"e 100\r7\b")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, r"\r\n~?[\-#]$")
        self.assertRegex(self.buffer, r"\r\n[0-9A-Fa-f:]{9,13} +26\.7\x08 \x08$")
        self.buffer = ""
        os.write(self.m, b".")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        os.write(self.m, b"h byte [100]\r")
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"\r\n0*26 ")

    def test_rc(self):
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"rc.replace r\rrc\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(1, len(re.findall(
            r"\r\n~?[&%]", self.buffer)))
        self.assertEqual(1, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        os.write(self.m, b"rc.append r;r\rrc\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertEqual(3, len(re.findall(
            r"\r\n~?[&%]", self.buffer)))
        self.assertEqual(3, len(re.findall(
            r"\r\n[0-9A-Fa-f:]{9,13} +[0-9A-Fa-f]{2,} ", self.buffer)))
        self.buffer = ""
        self.do_write_long("""
            rc.replace @:loop; @r ax +:= 1; @r ax .; @if (ax <= 4) then goto :loop
            r ax := 0
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"rc\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("if", self.buffer)
        self.assertNotIn("goto", self.buffer)
        self.assertNotIn("loop", self.buffer)
        self.assertEqual(0, len(re.findall(
            r"\r\n~?[&%]", self.buffer)))
        self.assertEqual(5, len(re.findall(
            r"\r\nAX +[0-9A-Fa-f]{4}", self.buffer)))
        self.assertNotRegex(self.buffer, r"\r\n~?[&%]$")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        self.do_write_long("""
            rc.replace re
            re.replace @:loop; @r ax +:= 1; @if (ax <= 40) then goto :loop
            r ax := 0
            r rclimit := 10
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"rc\r")
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn(" processing reached ", self.buffer)
        self.assertNotIn("if", self.buffer)
        self.assertNotIn("goto", self.buffer)
        self.assertNotIn("loop", self.buffer)
        self.assertEqual(1, len(re.findall(
            r"\r\n~?[&%]", self.buffer)))
        self.assertNotRegex(self.buffer, r"\r\n~?[&%]$")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")
        self.buffer = ""
        self.do_write_long("""
            rc.replace y scripts/loop.sld
            r ax := 0
            r rclimit := 10
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"rc\r")
        self.do_read(sleepduration = 0.2)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn(" processing reached ", self.buffer)
        self.assertNotIn("if", self.buffer)
        self.assertNotIn("goto", self.buffer)
        self.assertNotIn(":loop", self.buffer)
        self.assertEqual(1, len(re.findall(
            r"\r\n~?[&%]", self.buffer)))
        self.assertNotRegex(self.buffer, r"\r\n~?[&%]$")
        self.assertRegex(self.buffer, r"\r\n~?[\-#]$")

    def test_ext_extlib(self):
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        os.write(self.m, b"ext extlib.eld help\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"EXT LIB command",
            "ext lib help string not found")
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld help describe\r")
        self.do_read(sleepduration = 0.15)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"List of contained ELDs:",
            "ext lib list string not found")
        list = re.search(r"(?s)List of contained ELDs:(.*)$", self.buffer)
        list = list.group(1)
        self.assertTrue(40 <= len(re.findall(
            r"(?m)^\S+\s+.*\.\s*$", list)))
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld help wide\r")
        self.do_read(sleepduration = 0.15)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"List of contained ELDs:",
            "ext lib list string not found")
        list = re.search(r"(?s)List of contained ELDs:(.*)$", self.buffer)
        list = list.group(1)
        self.assertTrue(4 <= len(re.findall(
            r"(?m)^(\S+\s+){0,10}\S+\s*$", list)))

    def test_ext_ldmem(self):
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        os.write(self.m, b"ext extlib.eld ldmem.eld mem\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?m)^Entry segment:\s*[0-9A-Fa-f]+\s+Size:\s*[0-9A-Fa-f]+\s+[0-9.]+\s*(KiB|KB|kB)\s*(selector: [0-9A-Fa-f]+\s*)?$",
            "entry segment not found")
        self.assertNotIn("Overlap!", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld ldmem.eld eld\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?m)^\"LINKCALL\"",
            "linkcall ELD not found")
        self.assertRegex(self.buffer,
            r"(?m)^Free space.*\"LDMEM\s*\"\)\s*$",
            "transient ldmem ELD not found")
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld ldmem.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("LDMEM installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ldmem eld\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?m)^\"LINKCALL\"",
            "linkcall ELD not found")
        self.assertRegex(self.buffer,
            r"(?m)^\"LDMEM\s*\"",
            "resident ldmem ELD not found")
        self.buffer = ""
        os.write(self.m, b"ldmem commandhandler\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"Command handlers:\s+Entry=[0-9A-Fa-f]+h, instance=[0-9A-Fa-f]+h, identifier=\"LDMEM\s*\"",
            "resident ldmem command handler not found")
        self.buffer = ""
        os.write(self.m, b"ldmem injecthandler\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"Command inject handlers:\s+Entry=0+h - No Command inject handler installed.",
            "no command inject handlers not found")
        self.buffer = ""
        os.write(self.m, b"ldmem stack\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"Stack size: [0-9]+ bytes")
        self.assertRegex(self.buffer,
            r"Heuristic match byte: [0-9A-Fa-f]+h")
        self.assertRegex(self.buffer,
            r"Heuristic unused stack: [0-9]+ bytes")
        size = re.search(r"Stack size: ([0-9]+) bytes", self.buffer)
        size = int(size.group(1))
        unused = re.search(r"Heuristic unused stack: ([0-9]+) bytes", self.buffer)
        unused = int(unused.group(1))
        self.assertTrue(size <= 8192)
        self.assertTrue(size >= 256)
        self.assertTrue(unused <= size)
        self.assertTrue(unused >= 64)
        self.buffer = ""
        os.write(self.m, b"ldmem history\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"History entries: [0-9]+")
        self.assertRegex(self.buffer,
            r"History bytes: [0-9]+ used \/ [0-9]+ total")
        self.assertRegex(self.buffer,
            r"Average history entry size is <= [0-9]+ bytes\.")
        search = re.search(r"History entries: ([0-9]+)", self.buffer)
        entries = int(search.group(1))
        search = re.search(r"History bytes: ([0-9]+) used \/ ([0-9]+) total", self.buffer)
        usedbytes = int(search.group(1))
        totalbytes = int(search.group(2))
        search = re.search(r"Average history entry size is <= ([0-9]+) bytes\.", self.buffer)
        average = int(search.group(1))
        self.assertTrue(entries >= 10)
        self.assertTrue(usedbytes >= 200)
        self.assertTrue(usedbytes <= 2000)
        self.assertTrue(totalbytes >= 1024)
        self.assertTrue(totalbytes <= 16384)
        self.assertTrue(average == math.floor((usedbytes + entries - 1) / entries))
        self.buffer = ""
        os.write(self.m, b"ldmem uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("LDMEM uninstalled.", self.buffer)

    def test_ext_aformat(self):
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld aformat.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AFORMAT installed.", self.buffer)
        self.buffer = ""
        self.do_write_long("""
            a 100
             nop
             int3
             mov ax, 4C00
             int 21
             org 100
             .
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        search = re.search(r"([0-9A-Fa-f:]{9,13} )nop", self.buffer)
        length = len(search.group(1))
        self.assertRegex(self.buffer,
            r"[0-9A-Fa-f:]{9,13} nop[\r\n]{1,2} {%s}90\s" % length)
        search = re.search(r"([0-9A-Fa-f:]{9,13} )int3", self.buffer)
        length = len(search.group(1))
        self.assertRegex(self.buffer,
            r"[0-9A-Fa-f:]{9,13} int3[\r\n]{1,2} {%s}CC\s" % length)
        search = re.search(r"([0-9A-Fa-f:]{9,13} )mov ax, 4C00", self.buffer)
        length = len(search.group(1))
        self.assertRegex(self.buffer,
            r"[0-9A-Fa-f:]{9,13} mov ax, 4C00[\r\n]{1,2} {%s}(66)?B8004C\s" % length)
        search = re.search(r"([0-9A-Fa-f:]{9,13} )int 21", self.buffer)
        length = len(search.group(1))
        self.assertRegex(self.buffer,
            r"[0-9A-Fa-f:]{9,13} int 21[\r\n]{1,2} {%s}CD21\s" % length)
        self.assertRegex(self.buffer,
            r"[0-9A-Fa-f:]{9,13} org 100[\r\n]{1,2}[0-9A-Fa-f:]{9,13} .\s")
        self.buffer = ""
        os.write(self.m, b"aformat uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AFORMAT uninstalled.", self.buffer)

    def test_ext_checksum(self):
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld checksum.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("CHECKSUM command installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"e 100 0 1 2 3 4 5 6 7\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 0\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 1\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"00*1F\s")
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 2\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"0*3C2\s")
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 3\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"0*7480\s")
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 4\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"0*1B83\s")
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 5\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"0*54E1\s")
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 6\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"0*4744\s")
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 7\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"0*A142\s")
        self.buffer = ""
        os.write(self.m, b"checksum 100 l 8\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"0*8705\s")
        self.buffer = ""
        os.write(self.m, b"checksum list 0 1 2 3 4 5 6 7\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"0*8705\s")
        self.buffer = ""
        os.write(self.m, b"checksum uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("CHECKSUM command uninstalled.", self.buffer)

    def test_ext_list(self):
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld list.eld\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("Run with a pathname as parameter.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld list.eld extlib.eld verbose help\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read(0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?i)extlib.eld:\s+EXT LIB: library of ELDs\.\s")
        self.assertRegex(self.buffer,
            r"  Format: \"ELD[0-9]+\", ELD name: \"EXTLIB\s*\"\s")
        self.assertRegex(self.buffer,
            r"  [0-9]+ code, [0-9]+ alloc, [0-9]+ data, [0-9]+ alloc\s")
        self.assertRegex(self.buffer,
            r"EXT LIB command\. This ELD is a library of other ELDs\.\s")

    def test_ext_amitsrs(self):
        os.write(self.m, b"uninstall paging\rinstall amis\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld amitsrs.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMITSRS installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"amitsrs\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\secm\s+lDebug\s+.*lDebug.*, debugger\.\s")
        self.buffer = ""
        os.write(self.m, b"amitsrs int\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\secm\s+lDebug\s+.*lDebug.*, debugger\.\s")
        self.assertRegex(self.buffer,
            r"\schained interrupts:")
        self.assertRegex(self.buffer,
            r"03h at [0-9A-Fa-f]{4}h:[0-9A-Fa-f]{4}h")
        self.assertRegex(self.buffer,
            r"2Dh at [0-9A-Fa-f]{4}h:[0-9A-Fa-f]{4}h")
        self.buffer = ""
        os.write(self.m, b"amitsrs mpx\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\secm\s+lDebug\s+.*lDebug.*, debugger\.\s")
        self.assertRegex(self.buffer,
            r"\smultiplex 00h\s")
        self.buffer = ""
        os.write(self.m, b"amitsrs verbose\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\secm\s+lDebug\s+.*lDebug.*, debugger\.\s")
        self.assertRegex(self.buffer,
            r"\schained interrupts:")
        self.assertRegex(self.buffer,
            r"03h at [0-9A-Fa-f]{4}h:[0-9A-Fa-f]{4}h")
        self.assertRegex(self.buffer,
            r"2Dh at [0-9A-Fa-f]{4}h:[0-9A-Fa-f]{4}h")
        self.assertRegex(self.buffer,
            r"\smultiplex 00h\s")
        self.assertRegex(self.buffer,
            r"\sno hotkeys\s")
        self.buffer = ""
        os.write(self.m, b"amitsrs uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMITSRS uninstalled.", self.buffer)

    def test_ext_reclaim(self):
        os.write(self.m, b"uninstall paging\rinstall nofreeoneshot\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld reclaim.eld\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld ldmem.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("LDMEM installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ldmem eld\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer,
            r"(?m)^Free space.*\"",
            "transient ELD found")
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld help\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ldmem eld\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?m)^Free space.*\"",
            "transient ELD not found")
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld reclaim.eld\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ldmem eld\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer,
            r"(?m)^Free space.*\"",
            "transient ELD found")

    def test_ext_amount(self):
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld amount.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMOUNT installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"h eldamount\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        search = re.search(r"(?m)^([0-9A-Fa-f]+)  decimal: [0-9]+\s*$", self.buffer)
        self.assertTrue(search is not None)
        oldamount = int(search.group(1), 16)
        self.assertTrue(oldamount is not None)
        self.assertTrue(oldamount >= 2)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld ldmem.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("LDMEM installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"h eldamount\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        search = re.search(r"(?m)^([0-9A-Fa-f]+)  decimal: [0-9]+\s*$", self.buffer)
        self.assertTrue(search is not None)
        newamount = int(search.group(1), 16)
        self.assertTrue(newamount is not None)
        self.assertTrue(newamount >= 3)
        self.assertTrue(newamount == oldamount + 1)
        self.buffer = ""
        os.write(self.m, b"ldmem uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("LDMEM uninstalled.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"amount uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMOUNT uninstalled.", self.buffer)

    def test_ext_alias(self):
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld alias.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("ALIAS installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"alias list\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("No aliases defined currently.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"alias add testalias rvm\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"alias list\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"(?i)TESTALIAS\s+rvm\s")
        self.buffer = ""
        os.write(self.m, b"alias list qux\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("No such alias defined.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"testalias\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, "\sEntry segment=[0-9A-Fa-f]+h?\s")
        self.buffer = ""
        os.write(self.m, b"alias del testalias\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"alias list testalias\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("No such alias defined.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"alias list\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("No aliases defined currently.", self.buffer)
        self.assertNotRegex(self.buffer, r"(?i)TESTALIAS\s+rvm\s")
        self.buffer = ""
        os.write(self.m, b"alias uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("ALIAS uninstalled.", self.buffer)

    @unittest.skipIf(booting, "test is non-booting only")
    def test_ext_dosseek(self):
        self.do_write_long("""
            a 100
             mov dx, 200
             mov ax, 3D00
             int 21
             xchg bx, ax
             nop
             int3
             nop
             .
            e ds:200 "\extlib.eld",0
            g=100
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer, "(?m) CY\s*$")
        search = re.search(r" BX=([0-9A-Fa-f]{4}) ", self.buffer)
        self.assertTrue(search is not None)
        handlestring = search.group(1)
        self.assertTrue(handlestring is not None)
        handlenumber = int(handlestring, 16)
        self.buffer = ""
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, ("ext extlib.eld dosseek.eld get %s\r" % handlestring).encode())
        if self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("No free process handle in the debugger process!", self.buffer)
        self.assertNotIn("DUP error in the debugger process!", self.buffer)
        self.assertNotIn("Got I/O error trying to query current seek!", self.buffer)
        self.assertNotIn("Got I/O error trying to seek!", self.buffer)
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is beyond PHT size ")
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is closed\s")
        self.assertRegex(self.buffer,
            r"Process handle\s+%s\s+current seek is\s+0000_0000" % handlenumber)
        self.buffer = ""
        os.write(self.m, ("ext extlib.eld dosseek.eld set %s abs 1000\r" % handlestring).encode())
        if self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("No free process handle in the debugger process!", self.buffer)
        self.assertNotIn("DUP error in the debugger process!", self.buffer)
        self.assertNotIn("Got I/O error trying to query current seek!", self.buffer)
        self.assertNotIn("Got I/O error trying to seek!", self.buffer)
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is beyond PHT size ")
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is closed\s")
        self.buffer = ""
        os.write(self.m, ("ext extlib.eld dosseek.eld get %s\r" % handlestring).encode())
        if self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("No free process handle in the debugger process!", self.buffer)
        self.assertNotIn("DUP error in the debugger process!", self.buffer)
        self.assertNotIn("Got I/O error trying to query current seek!", self.buffer)
        self.assertNotIn("Got I/O error trying to seek!", self.buffer)
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is beyond PHT size ")
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is closed\s")
        self.assertRegex(self.buffer,
            r"Process handle\s+%s\s+current seek is\s+0000_1000" % handlenumber)
        self.buffer = ""
        os.write(self.m, ("ext extlib.eld dosseek.eld set %s eof 0\r" % handlestring).encode())
        if self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("No free process handle in the debugger process!", self.buffer)
        self.assertNotIn("DUP error in the debugger process!", self.buffer)
        self.assertNotIn("Got I/O error trying to query current seek!", self.buffer)
        self.assertNotIn("Got I/O error trying to seek!", self.buffer)
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is beyond PHT size ")
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is closed\s")
        self.buffer = ""
        os.write(self.m, ("ext extlib.eld dosseek.eld get %s\r" % handlestring).encode())
        if self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("No free process handle in the debugger process!", self.buffer)
        self.assertNotIn("DUP error in the debugger process!", self.buffer)
        self.assertNotIn("Got I/O error trying to query current seek!", self.buffer)
        self.assertNotIn("Got I/O error trying to seek!", self.buffer)
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is beyond PHT size ")
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is closed\s")
        self.assertRegex(self.buffer,
            r"Process handle\s+%s\s+current seek is\s+" % handlenumber)
        search = re.search(r"Process handle\s+%s\s+current seek is\s+([0-9A-Fa-f]{4})_([0-9A-Fa-f]{4}) " % handlenumber,
            self.buffer)
        self.assertTrue(search is not None)
        sizestring = search.group(1) + search.group(2)
        self.assertTrue(sizestring is not None)
        sizenumber = int(sizestring, 16)
        self.assertTrue(os.path.getsize(SCRIPTDIR / "extlib.eld") == sizenumber)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld dosseek.eld get #19\r")
        if self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("No free process handle in the debugger process!", self.buffer)
        self.assertNotIn("DUP error in the debugger process!", self.buffer)
        self.assertNotIn("Got I/O error trying to query current seek!", self.buffer)
        self.assertNotIn("Got I/O error trying to seek!", self.buffer)
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is beyond PHT size ")
        self.assertRegex(self.buffer,
            r"Process handle [0-9]+ is closed\s")
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld dosseek.eld get FFFF\r")
        if self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("No free process handle in the debugger process!", self.buffer)
        self.assertNotIn("DUP error in the debugger process!", self.buffer)
        self.assertNotIn("Got I/O error trying to query current seek!", self.buffer)
        self.assertNotIn("Got I/O error trying to seek!", self.buffer)
        self.assertRegex(self.buffer,
            r"Process handle [0-9]+ is beyond PHT size ")
        self.assertNotRegex(self.buffer,
            r"Process handle [0-9]+ is closed\s")

    def test_ext_history(self):
        os.write(self.m, b"uninstall paging\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld history.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("HISTORY utility installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"history show\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("uninstall paging", self.buffer)
        self.assertIn("ext extlib.eld history.eld install", self.buffer)
        self.assertRegex(self.buffer, "(?m)^history show\s*~?[-#]")
        self.buffer = ""
        os.write(self.m, b"history clear\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"history show\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("uninstall paging", self.buffer)
        self.assertNotIn("ext extlib.eld history.eld install", self.buffer)
        self.assertNotIn("history clear", self.buffer)
        self.assertRegex(self.buffer, "(?m)^history show\s*~?[-#]")
        self.buffer = ""
        os.write(self.m, b"history uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("HISTORY utility uninstalled.", self.buffer)

    def test_ext_amismsg(self):
        os.write(self.m, b"uninstall paging\rinstall amis\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld amismsg.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMIS message display installed.", self.buffer)
        self.buffer = ""
        os.write(self.m, b"amismsg display\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"amismsg display\s+~?[-#]$")
        self.buffer = ""
        if self.dpmisubtest:
            os.write(self.m, b"h linear ds:0\r")
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?m)^0*([0-9A-Fa-f]+)0  decimal:")
            search = re.search(r"(?m)^0*([0-9A-Fa-f]+)0  decimal:", self.buffer)
            self.assertTrue(search is not None)
            segment = search.group(1)
            self.assertTrue(segment is not None)
            self.buffer = ""
        else:
            segment = "ds"
        self.do_write_long("""
            a 100
             mov ax, (40 + amisnum * 100)
             mov dx, %s
             mov bx, 200
             int 2D
             nop
             int3
             nop
             .
            e ds:200 "AMIS test message",0D,0A,0
            """ % segment)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\sAX=[0-9A-Fa-f]{2}[Ff][Ff]\s")	# al=FFh message stored, not truncated
        self.assertRegex(self.buffer,
            r"\sAMIS test message\s+~?[-#]$")
        self.buffer = ""
        os.write(self.m, b"amismsg display\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotRegex(self.buffer,
            r"amismsg display\s+~?[-#]$")
        self.assertRegex(self.buffer,
            r"\sAMIS test message\s+~?[-#]$")
        self.buffer = ""
        self.do_write_long("""
            f ds:200 l 1000 "quux"
            e ds:200 + 1000 0
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\sAX=[0-9A-Fa-f]{2}[Ff][Ee]\s")	# al=FEh message stored, truncated
        self.assertRegex(self.buffer,
            r"(quux){64}")
        self.assertNotRegex(self.buffer,
            r"(quux){1024}")
        self.buffer = ""
        self.do_write_long("""
            a 100
             mov ax, (40 + amisnum * 100)
             mov dx, %s
             mov bx, 200
             int 2D
             mov di, ax
             mov ax, (41 + amisnum * 100)
             int 2D
             nop
             int3
             nop
             mov ax, (41 + amisnum * 100)
             int 2D
             nop
             int3
             nop
             .
            e ds:200 "AMIS test message",0D,0A,0
            """ % segment)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\sDI=[0-9A-Fa-f]{2}[Ff][Ff]\s")	# al=FFh message stored, not truncated
        self.assertRegex(self.buffer,
            r"\sAX=[0-9A-Fa-f]{2}02\s")	# al=02h message stored and not yet displayed
        self.assertRegex(self.buffer,
            r"\sAMIS test message\s+~?[-#]$")
        self.buffer = ""
        os.write(self.m, b"g\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\sAX=[0-9A-Fa-f]{2}01\s")	# al=01h no message stored or already displayed
        self.assertNotRegex(self.buffer,
            r"\sAMIS test message\s+~?[-#]$")
        self.buffer = ""
        os.write(self.m, b"amismsg uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMIS message display uninstalled.", self.buffer)

    def test_ext_amiscmd(self):
        os.write(self.m, b"uninstall paging\rinstall amis\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld amiscmd.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMIS command installed.", self.buffer)
        self.buffer = ""
        if self.dpmisubtest:
            os.write(self.m, b"h linear ds:0\r")
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertRegex(self.buffer,
                r"(?m)^0*([0-9A-Fa-f]+)0  decimal:")
            search = re.search(r"(?m)^0*([0-9A-Fa-f]+)0  decimal:", self.buffer)
            self.assertTrue(search is not None)
            segment = search.group(1)
            self.assertTrue(segment is not None)
            self.buffer = ""
        else:
            segment = "ds"
        self.do_write_long("""
            a 100
             mov ax, (43 + amisnum * 100)
             xor cx, cx
             mov dx, %s
             mov bx, 200
             int 2D
             nop
             int3
             nop
             .
            e ds:200 + 1 "rvm",0D
            r byte [ds:200] = aeo - (200 + 1 + 1)
            """ % segment)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\sAX=[0-9A-Fa-f]{2}[Ff][Ff]\s")	# al=FFh command stored
        self.assertRegex(self.buffer,
            r"\s~?[-#]rvm\s")
        self.assertRegex(self.buffer, r"\sEntry segment=[0-9A-Fa-f]+h?\s")
        self.buffer = ""
        self.do_write_long("""
            a 100
             mov ax, (43 + amisnum * 100)
             mov cx, FFFF
             mov dx, %s
             mov bx, 200
             int 2D
             nop
             int3
             nop
             .
            e ds:200 + 1 "rvm",0D
            r byte [ds:200] = aeo - (200 + 1 + 1)
            """ % segment)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\sAX=[0-9A-Fa-f]{2}02\s")	# al=02h command not stored, unknown flag in cx
        self.assertNotRegex(self.buffer,
            r"\s~?[-#]rvm\s")
        self.assertNotRegex(self.buffer, r"\sEntry segment=[0-9A-Fa-f]+h?\s")
        self.buffer = ""
        self.do_write_long("""
            a 100
             mov si, sp
             mov di, 4
             .
            r v0 := aao
            a
             mov ax, (43 + amisnum * 100)
             xor cx, cx
             mov dx, %s
             mov bx, 200
             int 2D
             push ax
             dec di
             jnz (v0)
             nop
             int3
             nop
             .
            e ds:200 + 1 "rvm",0D
            r byte [ds:200] = aeo - (200 + 1 + 1)
            """ % segment)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"r sp &= FFF0\rg=100\rdw ss:csp l 4 words\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\s[0-9A-Fa-f:]{9,13}\s+-([0-9A-Fa-f]{2}[Ff][Ff]\s+){4}")	# al=FFh command stored
        self.assertRegex(self.buffer,
            r"\s~?[-#]rvm\s")
        self.assertRegex(self.buffer, r"\sEntry segment=[0-9A-Fa-f]+h?\s")
        self.assertEqual(4, len(re.findall(
            r"\s~?[-#]rvm\s",
            self.buffer)))
        self.assertEqual(4, len(re.findall(
            r"\sEntry segment=[0-9A-Fa-f]+h?\s",
            self.buffer)))
        self.buffer = ""
        self.do_write_long("""
            a 100
             mov sp, si
             mov di, 10
             .
            r v0 := aao
            a
             mov ax, (43 + amisnum * 100)
             xor cx, cx
             mov dx, %s
             mov bx, 200
             int 2D
             push ax
             dec di
             jnz (v0)
             nop
             int3
             nop
             .
            f ds:201 l FE 20
            e ds:201 "rvm"
            e ds:201 + FE 0D
            r byte [ds:200] = aeo - (200 + 1 + 1)
            """ % segment)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"g=100\rdw ss:csp l 10 words\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\s[0-9A-Fa-f:]{9,13}\s+([0-9A-Fa-f]{4}[-\s])*([0-9A-Fa-f]{2}[Ff][Ff][-\s]){3}")	# al=FFh command stored
        self.assertRegex(self.buffer,
            r"\s[0-9A-Fa-f:]{9,13}\s+([0-9A-Fa-f]{2}01[-\s])+")	# al=01h command not stored, buffer overflow
        self.assertRegex(self.buffer,
            r"\s~?[-#]rvm\s")
        self.assertRegex(self.buffer, r"\sEntry segment=[0-9A-Fa-f]+h?\s")
        self.assertTrue(16 > len(re.findall(
            r"\s~?[-#]rvm\s",
            self.buffer)))
        self.assertTrue(3 <= len(re.findall(
            r"\s~?[-#]rvm\s",
            self.buffer)))
        self.assertTrue(16 > len(re.findall(
            r"\sEntry segment=[0-9A-Fa-f]+h?\s",
            self.buffer)))
        self.assertTrue(3 <= len(re.findall(
            r"\sEntry segment=[0-9A-Fa-f]+h?\s",
            self.buffer)))
        self.buffer = ""
        self.do_write_long("""
            a 100
             mov ax, (43 + amisnum * 100)
             xor cx, cx
             mov dx, %s
             mov bx, 200
             int 2D
             xchg di, ax
             mov ax, (43 + amisnum * 100)
             xor cx, cx
             mov dx, %s
             mov bx, 300
             int 2D
             nop
             int3
             nop
             .
            e ds:200 + 1 "r ax .",0D
            r byte [ds:200] = aeo - (200 + 1 + 1)
            e ds:300 + 1 "r bx .",0D
            r byte [ds:300] = aeo - (300 + 1 + 1)
            """ % (segment, segment), sleepduration = 0.05, sleepmodulo = 6)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\sDI=[0-9A-Fa-f]{2}[Ff][Ff]\s")	# al=FFh command stored
        self.assertRegex(self.buffer,
            r"\sAX=[0-9A-Fa-f]{2}[Ff][Ff]\s")	# al=FFh command stored
        self.assertRegex(self.buffer,
            r"\s~?[-#]r ax .\s")
        self.assertRegex(self.buffer,
            r"\s~?[-#]r bx .\s")
        self.assertRegex(self.buffer,
            r"(?sm)^AX [0-9A-Fa-f]+\s*$.*^BX [0-9A-Fa-f]+\s*$")
        self.buffer = ""
        os.write(self.m, b"amiscmd uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMIS command uninstalled.", self.buffer)

    def test_ext_amisoth(self):
        os.write(self.m, b"uninstall paging\rinstall amis\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"ext extlib.eld amisoth.eld install\r")
        if booting or self.dpmisubtest:
            time.sleep(0.05)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMIS other linker installed.", self.buffer)
        self.buffer = ""
        self.do_write_long("""
            a 100
             mov ax, (42 + amisnum * 100)
             xor dx, dx
             int 2D
             nop
             int3
             nop
             .
            r dpsp .
            """)
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?m)^DPSP ([0-9A-Fa-f]+)\s*$")
        search = re.search(r"(?m)^DPSP ([0-9A-Fa-f]+)\s*$", self.buffer)
        self.assertTrue(search is not None)
        segment = int(search.group(1), 16)
        self.assertTrue(segment is not None)
        self.buffer = ""
        os.write(self.m, b"g=100\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"\sAX=[0-9A-Fa-f]{2}[Ff][Ff]\s")	# al=FFh supported
        self.assertRegex(self.buffer,
            r"(?i)\sDX=%04X\s" % segment)
        self.buffer = ""
        os.write(self.m, b"r word [$bx:di] .\r")	# eldlSignature
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?mi)^WORD \[[0-9A-Fa-f:]{9,13}\] E1D1\s*$")
        self.buffer = ""
        os.write(self.m, b"r word [$bx:di + 6] .\r")	# eldlUseLinkHash
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?mi)^WORD \[[0-9A-Fa-f:]{9,13}\] 0*[01]\s*$")
        self.buffer = ""
        os.write(self.m, b"r word [$bx:di + 8] .\r")	# eldlDataAmount
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?mi)^WORD \[[0-9A-Fa-f:]{9,13}\] ([0-9A-Fa-f]+)\s*$")
        search = re.search(
            r"(?mi)^WORD \[[0-9A-Fa-f:]{9,13}\] ([0-9A-Fa-f]+)\s*$",
            self.buffer)
        self.assertTrue(search is not None)
        amount = int(search.group(1), 16)
        self.assertTrue(amount is not None)
        self.assertTrue(amount >= 64)
        self.assertTrue(amount <= 256)
        self.buffer = ""
        os.write(self.m, b"r word [$bx:di + 10] .\r")	# eldlCodeAmount
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer,
            r"(?mi)^WORD \[[0-9A-Fa-f:]{9,13}\] ([0-9A-Fa-f]+)\s*$")
        search = re.search(
            r"(?mi)^WORD \[[0-9A-Fa-f:]{9,13}\] ([0-9A-Fa-f]+)\s*$",
            self.buffer)
        self.assertTrue(search is not None)
        amount = int(search.group(1), 16)
        self.assertTrue(amount is not None)
        self.assertTrue(amount >= 64)
        self.assertTrue(amount <= 256)
        self.buffer = ""
        os.write(self.m, b"dw $bx:di l #12 words\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.buffer = ""
        os.write(self.m, b"amisoth uninstall\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertIn("AMIS other linker uninstalled.", self.buffer)

    def setup_dpmi(self, bit32 = 0):
        self.dpmisubtest = 1
        self.do_read()
        if self.debug:
            print(self.buffer)
        self.buffer = ""
        os.write(self.m, b"r dps .\r")
        self.do_read()
        if self.debug:
            print(self.buffer)
        if "^ Error" in self.buffer:
            raise unittest.SkipTest("build does not include dpmi")
        sleepduration = 0.05
        sleepmodulo = 4
        self.buffer = ""
        if self.dpmiexe is not None:
            self.do_write_long("""
                n %s
                l
                g
                """ % self.dpmiexe)
            self.do_read()
            if self.debug:
                print(self.buffer)
            self.assertNotIn("^ Error", self.buffer)
            self.assertNotIn("File not found", self.buffer)
            self.assertNotIn("Path not found", self.buffer)
            self.assertNotIn("Access denied", self.buffer)
            self.assertNotIn("Insufficient memory", self.buffer)
            self.assertNotRegex(self.buffer, r"Error .* opening file")
            self.buffer = ""
        if not bit32:
            string = "Protected mode breakpoint at "
        else:
            string = "32-bit code segment breakpoint at "
        self.do_write_long("""
            n %sdpmimini.com
            l
            s 100 l bxcx "%s"
            """ % (self.dpmidir, string),
            sleepmodulo = 2, sleepduration = 0.1)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertNotIn("File not found", self.buffer)
        self.assertNotIn("Path not found", self.buffer)
        self.assertNotIn("Access denied", self.buffer)
        self.assertNotIn("Insufficient memory", self.buffer)
        self.assertNotRegex(self.buffer, r"Error .* opening file")
        self.assertIn("DPMI entry hooked", self.buffer)
        p = re.compile(r"\r\n[0-9A-Fa-f:]{9}(?: \+[0-9A-Fa-f]{2,8})?  "
            + r"([0-9A-Fa-f]{2}[- ]){16}([0-9A-Fa-f]{4})h"
            + r".*\r\n0001 matches\r\n")
        self.assertRegex(self.buffer, p)
        m = p.search(self.buffer)
        self.assertTrue(m is not None)
        breakpoint = m.group(2)
        self.assertTrue(breakpoint is not None)
        self.buffer = ""
        self.do_write_long("""
            g
            g %s
            """ % breakpoint)
        self.do_read(sleepduration = 0.1)
        if self.debug:
            print(self.buffer)
        self.assertNotIn("^ Error", self.buffer)
        self.assertRegex(self.buffer, r"[\r\n]~?#$")
        self.buffer = ""

def add_dynamo_dpmi_test(classname, dynamoname, bit32, bit16, ww):
    @unittest.skipIf(booting, "test is non-booting only")
    @unittest.skipIf("x" not in build_name, "build does not include dpmi")
    @unittest.skipIf(not dpmiavailable, "dpmi not available")
    def test_innerdynamo_16(self):
        self.setup_dpmi(bit32 = 0)
        if dynamoname != "":
            getattr(self, "test_%s" % dynamoname)()
    @unittest.skipIf(booting, "test is non-booting only")
    @unittest.skipIf("x" not in build_name, "build does not include dpmi")
    @unittest.skipIf(not dpmiavailable, "dpmi not available")
    def test_innerdynamo_32(self):
        self.setup_dpmi(bit32 = 1)
        if dynamoname != "":
            getattr(self, "test_%s" % dynamoname)()
    if bit16:
        test_innerdynamo_16.__name__ = "test_%s_dpmi16%s" % (dynamoname, ww)
        setattr(classname, test_innerdynamo_16.__name__, test_innerdynamo_16)
    if bit32:
        test_innerdynamo_32.__name__ = "test_%s_dpmi32%s" % (dynamoname, ww)
        setattr(classname, test_innerdynamo_32.__name__, test_innerdynamo_32)

if __name__ == '__main__':
    dynamotests = [
        ("",),
        ("ext_extlib",),
        ("ext_ldmem",),
        ("ext_aformat",),
        ("ext_checksum",),
        ("ext_list",),
        ("ext_amitsrs",),
        ("ext_reclaim",),
        ("ext_amount",),
        ("ext_alias",),
        ("ext_dosseek",),
        ("ext_history",),
        ("ext_amismsg",),
        ("ext_amiscmd",),
        ("ext_amisoth",),
        ("beep", 1, 0, "_w1"),
        ("build", 1, 0, "_w1"),
        ("rh", 1, 0, "_w1"),
        ("dt", 1, 0, "_w1"),
        ("aa_basic", 1, 0, "_w2"),
        ("rr_basic", 1, 0, "_w1"),
        ("misc", 1, 0, "_w2"),
        ("bb_gg", 1, 0, "_w2"),
        ("bb_fill", 1, 0, "_w2"),
        ("access_var", 1, 0, "_w2"),
        ("missing_executable", 1, 0, "_w1"),
        ("error_executable", 1, 0, "_w1"),
        ("yy", 1, 0, "_w1"),
        ("eee_interactive", 1, 0, "_w1"),
        ("rc", 1, 0, "_w1"),
        ]
    for tuple in dynamotests:
        name = tuple[0]
        if len(tuple) >= 2:
            bit32 = tuple[1]
        else:
            bit32 = 1
        if len(tuple) >= 3:
            bit16 = tuple[2]
        else:
            bit16 = 1
        if len(tuple) >= 4:
            ww = tuple[3]
        else:
            ww = ""
        add_dynamo_dpmi_test(lDebugTest, name, bit32, bit16, ww)
    unittest.main()
