#!@PYTHON@ -t
# -*- Python -*-
# $Id: test.py.in,v 1.45 2008/12/26 02:40:45 rockyb Exp $
"Unit test for the Extended Python debugger's disassembler."
import difflib, os, time, sys, unittest

top_builddir = "@top_builddir@"
if top_builddir[-1] != os.path.sep:
    top_builddir += os.path.sep
sys.path.insert(0, os.path.join(top_builddir, 'pydb'))
top_srcdir = "@top_srcdir@"
if top_srcdir[-1] != os.path.sep:
    top_srcdir += os.path.sep
sys.path.insert(0, os.path.join(top_srcdir, 'pydb'))

import pydb

class PdbTest(pydb.Pdb):
    def __init__(self):
        pydb.Pdb.__init__(self)
        self.errLines = []
        self.msgLines = []
        self.msg_last_nocr = False
        self.stack = self.curframe = self.botframe = None
        return

    def errmsg(self, msg):
        self.errLines.append(msg)
        return

    def msg(self, msg):
        if self.msg_last_nocr:
            self.msgLines[-1] += msg
        else:
            self.msgLines.append(msg)
        self.msg_last_nocr = False
        return

    def msg_nocr(self, msg):
        if self.msg_last_nocr:
            self.msgLines[-1] += msg
        else:
            self.msgLines.append(msg)
        self.msg_last_nocr = True
        return

    def msgReset(self):
        self.msgLines = []
        return

builddir     = "@builddir@"
if builddir[-1] != os.path.sep:
    builddir += os.path.sep

srcdir = "@srcdir@"
if srcdir[-1] != os.path.sep:
    srcdir += os.path.sep

pydir        = os.path.join(top_builddir, "pydb")
pydb_short   = "pydb.py"
pydb_path    = os.path.join(pydir, pydb_short)

# FIXME! combine truncate and ingore_lines into a filter function
# (create with lambda). And move all of this out to a helper function
# anyway.
def run_debugger(testname, pythonfile, args='', outfile=None,
                 rightfile=None, pydb_opts='', truncate=None,
                 cmdfile=None, ignore_line=None):
    global srcdir, builddir, pydir
    if cmdfile is None:
        cmdfile     = os.path.join(srcdir, "%s.cmd" % testname)
    outfile_opt = ''
    if outfile is None:
        test_dir    = "@top_srcdir@"

        outfile     = os.path.join("@top_srcdir@", "test",
                                   "%s.out" % testname)
        outfile_opt = '--output=%s ' % outfile

    if rightfile is None:
        rightfile = os.path.join(srcdir, 'data',
                                 "%s.right" % testname)

    # print "builddir: %s, cmdfile: %s, outfile: %s, rightfile: %s" % \
    # (builddir, cmdfile, outfile, rightfile)

    if os.path.exists(outfile): os.unlink(outfile)

    os.environ['PYTHONPATH']=os.pathsep.join(sys.path)
    cmd = "%s %s --command %s %s %s %s" % \
          (pydb_path, pydb_opts, cmdfile, outfile_opt, pythonfile, args)
    
    os.system(cmd)
    fromfile  = rightfile
    fromdate  = time.ctime(os.stat(fromfile).st_mtime)
    fromlines = open(fromfile, 'U').readlines()
    tofile    = outfile
    todate    = time.ctime(os.stat(tofile).st_mtime)
    tolines   = open(tofile, 'U').readlines()

    if truncate:
        fromlines = fromlines[0:truncate]
        tolines   = tolines[0:truncate]
    if ignore_line:
        del fromlines[ignore_line]
        del tolines[ignore_line]

    diff = list(difflib.unified_diff(fromlines, tolines, fromfile,
                                     tofile, fromdate, todate))
    if len(diff) == 0: os.unlink(outfile)
    for line in diff: print line,
    return len(diff) == 0
    
class PdbTests(unittest.TestCase):

    def test_brkpt(self):
        """Unit test breakpoint setting and display - part 1."""

        if sys.hexversion >= 0x2073f0:
            rightfile = os.path.join(srcdir, 'data', "brkpt1-2.7.right")
        else:
            rightfile = os.path.join(srcdir, 'data', "brkpt1.right")
        result=run_debugger(testname='brkpt1',
                            pythonfile='%shanoi.py' % srcdir,
                            rightfile=rightfile)
        self.assertEqual(True, result, "brkpt1")
        #############################################################
        if sys.hexversion >= 0x2073f0:
            rightfile = os.path.join(srcdir, 'data', "brkpt1t-2.7.right")
        else:
            rightfile = os.path.join(srcdir, 'data', "brkpt1t.right")
        result=run_debugger(testname='brkpt1',
                            pythonfile='%shanoi.py' % srcdir,
                            pydb_opts='--threading',
                            rightfile=rightfile,
                            truncate=-2)
        self.assertEqual(True, result, "brkpt1 --threading")

    def test_brkpt2(self):
        """Unit test breakpoint setting and display - part 2."""
        if sys.hexversion <= 0x020400f0:
            rightfile = os.path.join(srcdir, 'data',
                                     "brkpt2-2.3.right")
        else:
            rightfile = os.path.join(srcdir, 'data',
                                     "brkpt2.right")
        result=run_debugger(testname='brkpt2',
                            pythonfile='%sgcd.py' % srcdir,
                            args='3 5',
                            rightfile=rightfile)
        self.assertEqual(True, result, "brkpt2")

    def test_brkpt3(self):
        """Unit test breakpoint setting and display - part 3."""
        cmdfile=os.path.join(builddir, 'brkpt3.cmd')
        result=run_debugger(testname='brkpt3',
                            pythonfile='%sgcd.py' % srcdir,
                            rightfile=os.path.join(srcdir, 'data',
                                                   "brkpt3.right"),
                            args='3 5',
                            truncate=-5,
                            ignore_line=19,
                            cmdfile=cmdfile)
        self.assertEqual(True, result, "brkpt3")
        if sys.hexversion >= 0x02050000:
            rightfile = os.path.join(srcdir, 'data', "brkpt3-2.5t.right")
        else:
            rightfile = os.path.join(srcdir, 'data', "brkpt3t.right")
        result=run_debugger(testname='brkpt3',
                            pythonfile='%sgcd.py' % srcdir,
                            args='3 5',
                            pydb_opts='--threading',
                            rightfile=rightfile,
                            truncate=-2,
                            ignore_line=20,
                            cmdfile=cmdfile)
        self.assertEqual(True, result, "brkpt3 --threading")

    def test_cmdparse(self):
        """Unit test command parsing."""
        result=run_debugger(testname='cmdparse',
                            pythonfile='%shanoi.py' % srcdir)
        self.assertEqual(True, result, "cmdparse")

    def test_complete(self):
        """Test the 'complete' command."""
        pdb = PdbTest()
        pdb.noninteractive = True
        if hasattr(pdb, 'do_complete'):
            print "Have complete"
            pdb.do_complete("c")
            correct = ['c', 'cd', 'cl', 'clear', 'commands',
                       'condition', 'continue']
            self.failUnless(  pdb.msgLines == correct,
                              "Completion is not complete"  )
            pdb.msgReset()
            pdb.do_complete("set i")
            correct = ['set interactive']
            self.failUnless(  pdb.msgLines == correct,
                              "Subcommand completion is not complete"  )
            pdb.msgReset()
            pdb.do_complete("info l")
            correct = ['info line', 'info locals']
            self.failUnless(  pdb.msgLines == correct,
                              "Subcommand completion (info l) not complete"  )
            pdb.msgReset()
            pdb.do_complete("complete handler foo")
            correct = []
            self.failUnless(  pdb.msgLines == correct,
                              "Subcommand completion (3) not complete"  )
            pdb.msgReset()
            pdb.do_complete("complete hand foo")
            correct = []
            self.failUnless(  pdb.msgLines == correct,
                              "Subcommand completion (4) not complete"  )
        else:
            print "No complete"

##     def test_debug(self):
##         """Test (recursive) debug command"""
##         result=run_debugger(testname='debug',
##                             pythonfile='%shanoi.py' % srcdir)
##         self.assertEqual(True, result, "debug")

    def test_filebug(self):
        """Test __file__"""
        result=run_debugger(testname='filebug',
                            pythonfile='%sfilebug.py' %srcdir)
        self.assertEqual(True, result, "filebug")
        
    def test_handle(self):
        """Unit test handle processing."""
        result=run_debugger(testname='sighandler',
                            pythonfile='%shanoi.py' % srcdir)
        self.assertEqual(True, result, "sighandler")

    def test_history(self):
        """Test the 'history' debugger command."""
        try:
            import @READLINE@
        except ImportError:
            return
        result=run_debugger(testname='history',
                            pythonfile='%shanoi.py' % srcdir)
        self.assertEqual(True, result, "history")
        if os.path.exists("history.hst"): os.unlink("history.hst")

    def test_logging(self):
        """Test 'set logging' and 'show logging' debugger commands."""
        global top_builddir
        logfile=os.path.join(top_builddir, "test", "logging.out")
        result=run_debugger(testname='logging',
                            pythonfile='%shanoi.py' % srcdir,
                            outfile=logfile)
        self.assertEqual(True, result, "logging")

    def test_no_script(self):
        """Test running without a script."""
        result=run_debugger(testname='noscript',
                            pythonfile="")
        self.assertEqual(True, result, "running without a Python script")

    def test_pwd_cd(self):
        """Test the 'pwd' and 'cd' debugger commands."""
        pdb = PdbTest()
        pdb.noninteractive = True

        # Run pwd
        pdb.msgLines=[]; pdb.errLines=[]
        pdb.do_pwd("")
        self.assertEqual(True, len(pdb.errLines) == 0,
                         "pwd gave error: " + str(pdb.errLines))
        self.assertEqual(True, len(pdb.msgLines) == 1)
        my_cd = pdb.msgLines[0]

        # Run cd
        pdb.msgLines=[]; pdb.errLines=[]
        pdb.do_cd(".")
        self.assertEqual(True, len(pdb.errLines) == 0,
                         "cd gave error: " + str(pdb.errLines))
        self.assertEqual(True, len(pdb.msgLines) == 0)
        pdb.msgLines=[]; pdb.errLines=[]
        pdb.do_pwd("")
        self.assertEqual(True, pdb.msgLines[0] == my_cd)

##     def test_return(self):
##         """Test of run with return."""
##         if sys.version_info[0:2] == (2, 4) and sys.version_info[3] >= 2:
##             print
##             print "**********************************************************"
##             print "***                   NOTE                             ***"
##             print "*** The traceback 'Need to give two numbers' is right  ***"
##             print "**********************************************************"
##             result=run_debugger(testname='run2',
##                                 pythonfile='%sgcd.py' % srcdir)
##             self.assertEqual(True, result, "run2")

    def test_run(self):
        """Test 'run' and 'restart' debugger commands."""
        # Python 2.3.5 stack traces look different and I 
        # don't know enough about what version changes what. So for
        # now, we run the test and if it doesn't crash on anything
        # that is less than version 2.5 we'll call it a success.
        # For version 2.5 (and above?) we'll assume a more 
        # stringent test.
        if sys.hexversion > '20400f0':
            result=run_debugger(testname='run',
                                pythonfile='%shanoi.py' % srcdir)
            self.assertEqual(True, result, "run")

if __name__ == "__main__":
    unittest.main()
