Added a more complex test case of breakpoint commands, which executes a sequence

of 'breakpoint command add/list/remove' commands to set breakpoint callbacks,
list them, and then remove one.

Modified the lldbtest.TestBase.expect() method to add two additional keyword
arguments:

o matching (default to True), which, if set to False, reverses the semantics of
  'expect' to 'expect not'

o patterns (default to None), which specifies a list of regexp patterns to match
  against the output from running the command

TestBreakpointCommand.py uses the matching=False and the patterns=[...] expect()
API.

llvm-svn: 114480
This commit is contained in:
Johnny Chen 2010-09-21 21:08:53 +00:00
parent 99ff76212a
commit ea88e94318
4 changed files with 172 additions and 8 deletions

View File

@ -0,0 +1,5 @@
LEVEL = ../make
C_SOURCES := main.c
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,115 @@
"""
Test lldb breakpoint command add/list/remove.
"""
import os, time
import unittest2
import lldb
from lldbtest import *
class BreakpointCommandTestCase(TestBase):
mydir = "breakpoint_command"
@classmethod
def classCleanup(cls):
system(["/bin/sh", "-c", "rm output.txt"])
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
def test_with_dsym(self):
"""Test a sequence of breakpoint command add, list, and remove."""
self.buildDsym()
self.breakpoint_command_sequence()
def test_with_dwarf(self):
"""Test a sequence of breakpoint command add, list, and remove."""
self.buildDwarf()
self.breakpoint_command_sequence()
def breakpoint_command_sequence(self):
"""Test a sequence of breakpoint command add, list, and remove."""
exe = os.path.join(os.getcwd(), "a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
# Add two breakpoints on the same line.
self.expect("breakpoint set -f main.c -l 12", BREAKPOINT_CREATED,
startstr = "Breakpoint created: 1: file ='main.c', line = 12, locations = 1")
self.expect("breakpoint set -f main.c -l 12", BREAKPOINT_CREATED,
startstr = "Breakpoint created: 2: file ='main.c', line = 12, locations = 1")
# Now add callbacks for the breakpoints just created.
self.runCmd("breakpoint command add -c -o 'frame variable -s' 1")
self.runCmd("breakpoint command add -p -o 'here = open(\"output.txt\", \"w\"); print >> here, \"lldb\"; here.close()' 2")
# Check that the breakpoint commands are correctly set.
# The breakpoint list now only contains breakpoint 1.
self.expect("breakpoint list", "Breakpoints 1 & 2 created",
substrs = ["1: file ='main.c', line = 12, locations = 1",
"2: file ='main.c', line = 12, locations = 1"],
patterns = ["1.1: .+at main.c:12, .+unresolved, hit count = 0",
"2.1: .+at main.c:12, .+unresolved, hit count = 0"])
self.expect("breakpoint command list 1", "Breakpoint 1 command ok",
substrs = ["Breakpoint commands:",
"frame variable -s"])
self.expect("breakpoint command list 2", "Breakpoint 2 command ok",
substrs = ["Breakpoint commands:",
"here = open",
"print >> here",
"here.close()"])
# Run the program.
self.runCmd("run", RUN_SUCCEEDED)
# Check that the file 'output.txt' exists and contains the string "lldb".
# Read the output file produced by running the program.
output = open('output.txt', 'r').read()
self.assertTrue(output.startswith("lldb"),
"File 'output.txt' and the content matches")
# Finish the program.
self.runCmd("process continue")
# Remove the breakpoint command associated with breakpoint 1.
self.runCmd("breakpoint command remove 1")
# Remove breakpoint 2.
self.runCmd("breakpoint delete 2")
self.expect("breakpoint command list 1",
startstr = "Breakpoint 1 does not have an associated command.")
self.expect("breakpoint command list 2", error=True,
startstr = "error: '2' is not a currently valid breakpoint id.")
# The breakpoint list now only contains breakpoint 1.
self.expect("breakpoint list", "Breakpoint 1 exists",
substrs = ["1: file ='main.c', line = 12, locations = 1, resolved = 1",
"hit count = 1"])
# Not breakpoint 2.
self.expect("breakpoint list", "No more breakpoint 2", matching=False,
substrs = ["2: file ='main.c', line = 12, locations = 1, resolved = 1"])
# Run the program again, with breakpoint 1 remaining.
self.runCmd("run", RUN_SUCCEEDED)
# We should be stopped again due to breakpoint 1.
# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs = ['state is Stopped',
'stop reason = breakpoint'])
# The breakpoint should have a hit count of 2.
self.expect("breakpoint list", BREAKPOINT_HIT_ONCE,
substrs = ['resolved, hit count = 2'])
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View File

@ -0,0 +1,13 @@
//===-- main.c --------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
int main (int argc, char const *argv[])
{
return 0;
}

View File

@ -97,6 +97,7 @@ $
"""
import os, sys
import re
from subprocess import *
import time
import types
@ -399,19 +400,24 @@ class TestBase(unittest2.TestCase):
self.assertTrue(self.res.Succeeded(),
msg if msg else CMD_MSG(cmd))
def expect(self, cmd, msg=None, startstr=None, substrs=None, trace=False, error=False):
def expect(self, cmd, msg=None, patterns=None, startstr=None, substrs=None, trace=False, error=False, matching=True):
"""
Similar to runCmd; with additional expect style output matching ability.
Ask the command interpreter to handle the command and then check its
return status. The 'msg' parameter specifies an informational assert
message. We expect the output from running the command to start with
'startstr' and matches the substrings contained in 'substrs'.
'startstr', matches the substrings contained in 'substrs', and regexp
matches the patterns contained in 'patterns'.
If the keyword argument error is set to True, it signifies that the API
client is expecting the command to fail. In this case, the error stream
from running the command is retrieved and compared against the golden
input, instead.
If the keyword argument matching is set to False, it signifies that the API
client is expecting the output of the command not to match the golden
input.
"""
trace = (True if traceAlways else trace)
@ -426,25 +432,50 @@ class TestBase(unittest2.TestCase):
self.assertFalse(self.res.Succeeded(),
"Command '" + cmd + "' is expected to fail!")
matched = output.startswith(startstr) if startstr else True
# The heading says either "Expecting" or "Not expecting".
if trace:
heading = "Expecting" if matching else "Not expecting"
# Start from the startstr, if specified.
# If there's no startstr, set the initial state appropriately.
matched = output.startswith(startstr) if startstr else (True if matching else False)
if startstr and trace:
print >> sys.stderr, "Expecting start string:", startstr
print >> sys.stderr, "%s start string: %s" % (heading, startstr)
print >> sys.stderr, "Matched" if matched else "Not matched"
print >> sys.stderr
if substrs and matched:
# Look for sub strings, if specified.
keepgoing = matched if matching else not matched
if substrs and keepgoing:
for str in substrs:
matched = output.find(str) > 0
if trace:
print >> sys.stderr, "Expecting sub string:", str
print >> sys.stderr, "%s sub string: %s" % (heading, str)
print >> sys.stderr, "Matched" if matched else "Not matched"
if not matched:
keepgoing = matched if matching else not matched
if not keepgoing:
break
if trace:
print >> sys.stderr
self.assertTrue(matched, msg if msg else CMD_MSG(cmd))
# Search for regular expression patterns, if specified.
keepgoing = matched if matching else not matched
if patterns and keepgoing:
for pattern in patterns:
# Match Objects always have a boolean value of True.
matched = bool(re.search(pattern, output))
if trace:
print >> sys.stderr, "%s pattern: %s" % (heading, pattern)
print >> sys.stderr, "Matched" if matched else "Not matched"
keepgoing = matched if matching else not matched
if not keepgoing:
break
if trace:
print >> sys.stderr
self.assertTrue(matched if matching else not matched,
msg if msg else CMD_MSG(cmd))
def invoke(self, obj, name, trace=False):
"""Use reflection to call a method dynamically with no argument."""