[Lldb-commits] [lldb] r219984 - Added a new kind of test case: the "inline" test

Sean Callanan scallanan at apple.com
Thu Oct 16 16:15:22 PDT 2014


Author: spyffe
Date: Thu Oct 16 18:15:22 2014
New Revision: 219984

URL: http://llvm.org/viewvc/llvm-project?rev=219984&view=rev
Log:
Added a new kind of test case: the "inline" test
case.  This test case style attempts to shed all
of the boilerplate that is required for test
cases, and let 80% of test cases use a much terser
syntax.

Inline testcases have much simplified python files
(the corresponding .py file should contain two
lines of code) and require no Makefile, because the
Makefile is generated automatically.  Breakpoints
are set automatically and the indicated breakpoint
actions (specified after a magic //% comment) are
executed when the breakpoint is hit.

All other testcases are unaffected.

One thing I'm not really happy with yet is the way
multiple actions for the same line are specified.
I'm going to use lang/c/struct_types as a guinea
pig to develop this further.

Added:
    lldb/trunk/test/lldbinline.py
Removed:
    lldb/trunk/test/lang/c/struct_types/Makefile
    lldb/trunk/test/lang/c/struct_types/cmds.txt
Modified:
    lldb/trunk/test/lang/c/struct_types/TestStructTypes.py
    lldb/trunk/test/lang/c/struct_types/main.c

Removed: lldb/trunk/test/lang/c/struct_types/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/struct_types/Makefile?rev=219983&view=auto
==============================================================================
--- lldb/trunk/test/lang/c/struct_types/Makefile (original)
+++ lldb/trunk/test/lang/c/struct_types/Makefile (removed)
@@ -1,5 +0,0 @@
-LEVEL = ../../../make
-
-C_SOURCES := main.c
-
-include $(LEVEL)/Makefile.rules

Modified: lldb/trunk/test/lang/c/struct_types/TestStructTypes.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/struct_types/TestStructTypes.py?rev=219984&r1=219983&r2=219984&view=diff
==============================================================================
--- lldb/trunk/test/lang/c/struct_types/TestStructTypes.py (original)
+++ lldb/trunk/test/lang/c/struct_types/TestStructTypes.py Thu Oct 16 18:15:22 2014
@@ -1,102 +1,3 @@
-"""
-Test that break on a struct declaration has no effect.
+import lldbinline
 
-Instead, the first executable statement is set as the breakpoint.
-"""
-
-import os, time
-import unittest2
-import lldb
-from lldbtest import *
-import lldbutil
-
-class StructTypesTestCase(TestBase):
-
-    mydir = TestBase.compute_mydir(__file__)
-
-    # rdar://problem/12566646
-    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
-    @dsym_test
-    def test_with_dsym(self):
-        """Test that break on a struct declaration has no effect."""
-        self.buildDsym()
-        self.struct_types()
-
-    # rdar://problem/12566646
-    @expectedFailureIcc # llvm.org/pr16793
-                        # ICC generates DW_AT_byte_size zero with a zero-length 
-                        # array and LLDB doesn't process it correctly.
-    @dwarf_test
-    def test_with_dwarf(self):
-        """Test that break on a struct declaration has no effect."""
-        self.buildDwarf()
-        self.struct_types()
-
-    def setUp(self):
-        # Call super's setUp().
-        TestBase.setUp(self)
-        # Find the line number to break for main.c.
-        self.source = 'main.c'
-        self.line = line_number(self.source, '// Set break point at this line.')
-        self.first_executable_line = line_number(self.source,
-                                                 '// This is the first executable statement.')
-        self.return_line = line_number(self.source, '// This is the return statement.')
-
-    def struct_types(self):
-        """Test that break on a struct declaration has no effect and test structure access for zero sized arrays."""
-        exe = os.path.join(os.getcwd(), "a.out")
-
-        # Create a target by the debugger.
-        target = self.dbg.CreateTarget(exe)
-        self.assertTrue(target, VALID_TARGET)
-
-        # Break on the struct declration statement in main.c.
-        lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=False)
-        lldbutil.run_break_set_by_file_and_line (self, "main.c", self.return_line, num_expected_locations=1, loc_exact=True)
-
-        # Now launch the process, and do not stop at entry point.
-        process = target.LaunchSimple (None, None, self.get_process_working_directory())
-
-        if not process:
-            self.fail("SBTarget.Launch() failed")
-
-        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
-
-        # We should be stopped on the first executable statement within the
-        # function where the original breakpoint was attempted.
-        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
-            substrs = ['main.c:%d' % self.first_executable_line,
-                       'stop reason = breakpoint'])
-
-        # The breakpoint should have a hit count of 1.
-        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
-            substrs = [' resolved, hit count = 1'])
-
-        process.Continue()
-        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
-
-        # Test zero length array access and make sure it succeeds with "frame variable"
-        self.expect("frame variable pt.padding[0]",
-            DATA_TYPES_DISPLAYED_CORRECTLY,
-            substrs = ["pt.padding[0] = "])
-        self.expect("frame variable pt.padding[1]",
-            DATA_TYPES_DISPLAYED_CORRECTLY,
-            substrs = ["pt.padding[1] = "])
-        # Test zero length array access and make sure it succeeds with "expression"
-        self.expect("expression -- (pt.padding[0])",
-            DATA_TYPES_DISPLAYED_CORRECTLY,
-            substrs = ["(char)", " = "])
-
-        # The padding should be an array of size 0
-        self.expect("image lookup -t point_tag",
-            DATA_TYPES_DISPLAYED_CORRECTLY,
-            substrs = ['padding[]']) # Once rdar://problem/12566646 is fixed, this should display correctly
-
-        self.expect("expression -- &pt == (struct point_tag*)0",
-                    substrs = ['false'])
-
-if __name__ == '__main__':
-    import atexit
-    lldb.SBDebugger.Initialize()
-    atexit.register(lambda: lldb.SBDebugger.Terminate())
-    unittest2.main()
+lldbinline.MakeInlineTest(__file__, globals())

Removed: lldb/trunk/test/lang/c/struct_types/cmds.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/struct_types/cmds.txt?rev=219983&view=auto
==============================================================================
--- lldb/trunk/test/lang/c/struct_types/cmds.txt (original)
+++ lldb/trunk/test/lang/c/struct_types/cmds.txt (removed)
@@ -1,3 +0,0 @@
-break main.c:14
-continue
-var

Modified: lldb/trunk/test/lang/c/struct_types/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/struct_types/main.c?rev=219984&r1=219983&r2=219984&view=diff
==============================================================================
--- lldb/trunk/test/lang/c/struct_types/main.c (original)
+++ lldb/trunk/test/lang/c/struct_types/main.c Thu Oct 16 18:15:22 2014
@@ -12,13 +12,13 @@ int main (int argc, char const *argv[])
         int x;
         int y;
         char padding[0];
-    }; // Set break point at this line.
+    }; //% self.expect("frame variable pt.padding[0]", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["pt.padding[0] = "]); self.expect("frame variable pt.padding[1]", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["pt.padding[1] = "]); self.expect("expression -- (pt.padding[0])", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["(char)", " = "]); self.expect("image lookup -t point_tag", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ['padding[]']) # Once rdar://problem/12566646 is fixed, this should display correctly
 
     struct rect_tag {
         struct point_tag bottom_left;
         struct point_tag top_right;
     };
-    struct point_tag pt = { 2, 3, {} }; // This is the first executable statement.
+    struct point_tag pt = { 2, 3, {} }; //% self.
     struct rect_tag rect = {{1, 2, {}}, {3, 4, {}}};
-    return 0; // This is the return statement.
+    return 0; //% self.expect("expression -- &pt == (struct point_tag*)0", substrs = ['false'])
 }

Added: lldb/trunk/test/lldbinline.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbinline.py?rev=219984&view=auto
==============================================================================
--- lldb/trunk/test/lldbinline.py (added)
+++ lldb/trunk/test/lldbinline.py Thu Oct 16 18:15:22 2014
@@ -0,0 +1,161 @@
+import lldb
+from lldbtest import *
+import lldbutil
+import os
+import new
+
+def source_type(filename):
+    _, extension = os.path.splitext(filename)
+    return {
+        '.c' : 'C_SOURCES',
+        '.cpp' : 'CXX_SOURCES',
+        '.cxx' : 'CXX_SOURCES',
+        '.cc' : 'CXX_SOURCES',
+        '.m' : 'OBJC_SOURCES',
+        '.mm' : 'OBJCXX_SOURCES'
+    }.get(extension, None)
+
+class CommandParser:
+    def __init__(self):
+        self.breakpoints = []
+
+    def parse_one_command(self, line):
+        parts = line.split('//%')
+        if len(parts) != 2:
+            return None
+        else:
+            return parts[1].strip() # take off trailing whitespace
+
+    def parse_source_files(self, source_files):
+        for source_file in source_files:
+            file_handle = open(source_file)
+            lines = file_handle.readlines()
+            line_number = 0
+            for line in lines:
+                line_number = line_number + 1 # 1-based, so we do this first
+                command = self.parse_one_command(line)
+                if command != None:
+                    breakpoint = {}
+                    breakpoint['file_name'] = source_file
+                    breakpoint['line_number'] = line_number
+                    breakpoint['command'] = command
+                    self.breakpoints.append(breakpoint)
+
+    def set_breakpoints(self, target):
+        for breakpoint in self.breakpoints:
+            breakpoint['breakpoint'] = target.BreakpointCreateByLocation(breakpoint['file_name'], breakpoint['line_number'])
+
+    def handle_breakpoint(self, test, breakpoint_id):
+        for breakpoint in self.breakpoints:
+            if breakpoint['breakpoint'].GetID() == breakpoint_id:
+                test.execute_user_command(breakpoint['command'])
+                return
+
+def BuildMakefile(mydir):
+    categories = {}
+
+    for f in os.listdir(os.getcwd()):
+        t = source_type(f)
+        if t:
+            if t in categories.keys():
+                categories[t].append(f)
+            else:
+                categories[t] = [f]
+
+    makefile = open("Makefile", 'w+')
+
+    level = os.sep.join([".."] * len(mydir.split(os.sep))) + os.sep + "make"
+
+    makefile.write("LEVEL = " + level + "\n")
+   
+    for t in categories.keys():
+        line = t + " := " + " ".join(categories[t])
+        makefile.write(line + "\n")
+
+    if ('OBJCXX_SOURCES' in categories.keys()) or ('OBJC_SOURCES' in categories.keys()):
+        makefile.write("LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n")
+
+    if ('CXX_SOURCES' in categories.keys()):
+        makefile.write("CXXFLAGS += -std-c++11\n")
+
+    makefile.write("include $(LEVEL)/Makefile.rules\n")
+    makefile.flush()
+    makefile.close()
+
+def CleanMakefile():
+    if (os.path.isfile("Makefile")):
+        os.unlink("Makefile")
+
+class InlineTest(TestBase):
+    # Internal implementation
+
+    def buildDsymWithImplicitMakefile(self):
+        BuildMakefile(self.mydir)
+        self.buildDsym()
+
+    def buildDwarfWithImplicitMakefile(self):
+        BuildMakefile(self.mydir)
+        self.buildDwarf()
+
+    def test_with_dsym(self):
+        self.buildDsymWithImplicitMakefile()
+        self.do_test()
+
+    def test_with_dwarf(self):
+        self.buildDwarfWithImplicitMakefile()
+        self.do_test()
+
+    def execute_user_command(self, __command):
+        exec __command in globals(), locals()
+
+    def do_test(self):
+        exe_name = "a.out"
+        exe = os.path.join(os.getcwd(), exe_name)
+        source_files = [ f for f in os.listdir(os.getcwd()) if source_type(f) ]
+        target = self.dbg.CreateTarget(exe)
+
+        parser = CommandParser()
+        parser.parse_source_files(source_files)
+        parser.set_breakpoints(target)
+
+        process = target.LaunchSimple(None, None, os.getcwd())
+
+        while lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint):
+            thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+            breakpoint_id = thread.GetStopReasonDataAtIndex (0)
+            parser.handle_breakpoint(self, breakpoint_id)
+            process.Continue()
+
+    @classmethod
+    def classCleanup(cls):
+        CleanMakefile()
+
+    # Utilities for testcases
+
+    def check_expression (self, expression, expected_result, use_summary = True):
+        value = self.frame().EvaluateExpression (expression)
+        self.assertTrue(value.IsValid(), expression+"returned a valid value")
+        if self.TraceOn():
+            print value.GetSummary()
+            print value.GetValue()
+        if use_summary:
+            answer = value.GetSummary()
+        else:
+            answer = value.GetValue()
+        report_str = "%s expected: %s got: %s"%(expression, expected_result, answer)
+        self.assertTrue(answer == expected_result, report_str)
+
+def MakeInlineTest(__file, __globals):
+    # Derive the test name from the current file name
+    file_basename = os.path.basename(__file)
+    InlineTest.mydir = TestBase.compute_mydir(__file)
+
+    test_name, _ = os.path.splitext(file_basename)
+    # Build the test case 
+    test = new.classobj(test_name, (InlineTest,), {})
+    test.name = test_name
+    # Add the test case to the globals, and hide InlineTest
+    __globals.update({test_name : test})
+    del globals()["InlineTest"]
+
+





More information about the lldb-commits mailing list