blob: 37c57f39e882b0691e32a60ec626034e33faa8a9 [file] [log] [blame]
Sean Callanan816cb3e2014-10-16 23:15:22 +00001import lldb
2from lldbtest import *
3import lldbutil
4import os
5import new
Sean Callanane17428a2014-10-28 20:23:20 +00006import unittest2
7import sys
Sean Callanan816cb3e2014-10-16 23:15:22 +00008
9def source_type(filename):
10 _, extension = os.path.splitext(filename)
11 return {
12 '.c' : 'C_SOURCES',
13 '.cpp' : 'CXX_SOURCES',
14 '.cxx' : 'CXX_SOURCES',
15 '.cc' : 'CXX_SOURCES',
16 '.m' : 'OBJC_SOURCES',
17 '.mm' : 'OBJCXX_SOURCES'
18 }.get(extension, None)
19
20class CommandParser:
21 def __init__(self):
22 self.breakpoints = []
23
24 def parse_one_command(self, line):
25 parts = line.split('//%')
Sean Callanand950fa72014-10-17 00:39:37 +000026
27 command = None
28 new_breakpoint = True
29
30 if len(parts) == 2:
31 command = parts[1].strip() # take off whitespace
32 new_breakpoint = parts[0].strip() != ""
33
34 return (command, new_breakpoint)
Sean Callanan816cb3e2014-10-16 23:15:22 +000035
36 def parse_source_files(self, source_files):
37 for source_file in source_files:
38 file_handle = open(source_file)
39 lines = file_handle.readlines()
40 line_number = 0
Sean Callanand950fa72014-10-17 00:39:37 +000041 current_breakpoint = None # non-NULL means we're looking through whitespace to find additional commands
Sean Callanan816cb3e2014-10-16 23:15:22 +000042 for line in lines:
43 line_number = line_number + 1 # 1-based, so we do this first
Sean Callanand950fa72014-10-17 00:39:37 +000044 (command, new_breakpoint) = self.parse_one_command(line)
45
46 if new_breakpoint:
47 current_breakpoint = None
48
Sean Callanan816cb3e2014-10-16 23:15:22 +000049 if command != None:
Sean Callanand950fa72014-10-17 00:39:37 +000050 if current_breakpoint == None:
51 current_breakpoint = {}
52 current_breakpoint['file_name'] = source_file
53 current_breakpoint['line_number'] = line_number
54 current_breakpoint['command'] = command
55 self.breakpoints.append(current_breakpoint)
56 else:
57 current_breakpoint['command'] = current_breakpoint['command'] + "\n" + command
Sean Callanan816cb3e2014-10-16 23:15:22 +000058
59 def set_breakpoints(self, target):
60 for breakpoint in self.breakpoints:
61 breakpoint['breakpoint'] = target.BreakpointCreateByLocation(breakpoint['file_name'], breakpoint['line_number'])
62
63 def handle_breakpoint(self, test, breakpoint_id):
64 for breakpoint in self.breakpoints:
65 if breakpoint['breakpoint'].GetID() == breakpoint_id:
66 test.execute_user_command(breakpoint['command'])
67 return
68
69def BuildMakefile(mydir):
Zachary Turner54fa73a2014-12-19 18:26:33 +000070 if os.path.exists("Makefile"):
71 return
72
Sean Callanan816cb3e2014-10-16 23:15:22 +000073 categories = {}
74
75 for f in os.listdir(os.getcwd()):
76 t = source_type(f)
77 if t:
78 if t in categories.keys():
79 categories[t].append(f)
80 else:
81 categories[t] = [f]
82
83 makefile = open("Makefile", 'w+')
84
85 level = os.sep.join([".."] * len(mydir.split(os.sep))) + os.sep + "make"
86
87 makefile.write("LEVEL = " + level + "\n")
88
89 for t in categories.keys():
90 line = t + " := " + " ".join(categories[t])
91 makefile.write(line + "\n")
92
93 if ('OBJCXX_SOURCES' in categories.keys()) or ('OBJC_SOURCES' in categories.keys()):
94 makefile.write("LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n")
95
96 if ('CXX_SOURCES' in categories.keys()):
Enrico Granata4bd54a12014-10-22 20:33:34 +000097 makefile.write("CXXFLAGS += -std=c++11\n")
Sean Callanan816cb3e2014-10-16 23:15:22 +000098
99 makefile.write("include $(LEVEL)/Makefile.rules\n")
100 makefile.flush()
101 makefile.close()
102
103def CleanMakefile():
Zachary Turner54fa73a2014-12-19 18:26:33 +0000104 # Do nothing for now, since the Makefile on disk could be checked into the repo.
105 pass
Sean Callanan816cb3e2014-10-16 23:15:22 +0000106
107class InlineTest(TestBase):
108 # Internal implementation
109
Ed Mastee1b25362014-10-23 15:21:45 +0000110 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
Sean Callanan816cb3e2014-10-16 23:15:22 +0000111 def buildDsymWithImplicitMakefile(self):
112 BuildMakefile(self.mydir)
113 self.buildDsym()
114
115 def buildDwarfWithImplicitMakefile(self):
116 BuildMakefile(self.mydir)
117 self.buildDwarf()
118
Ed Mastee1b25362014-10-23 15:21:45 +0000119 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
Sean Callanane17428a2014-10-28 20:23:20 +0000120 def __test_with_dsym(self):
Sean Callanan816cb3e2014-10-16 23:15:22 +0000121 self.buildDsymWithImplicitMakefile()
122 self.do_test()
123
Sean Callanane17428a2014-10-28 20:23:20 +0000124 def __test_with_dwarf(self):
Sean Callanan816cb3e2014-10-16 23:15:22 +0000125 self.buildDwarfWithImplicitMakefile()
126 self.do_test()
127
128 def execute_user_command(self, __command):
129 exec __command in globals(), locals()
130
131 def do_test(self):
132 exe_name = "a.out"
133 exe = os.path.join(os.getcwd(), exe_name)
134 source_files = [ f for f in os.listdir(os.getcwd()) if source_type(f) ]
135 target = self.dbg.CreateTarget(exe)
136
137 parser = CommandParser()
138 parser.parse_source_files(source_files)
139 parser.set_breakpoints(target)
140
141 process = target.LaunchSimple(None, None, os.getcwd())
142
143 while lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint):
144 thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
145 breakpoint_id = thread.GetStopReasonDataAtIndex (0)
146 parser.handle_breakpoint(self, breakpoint_id)
147 process.Continue()
148
149 @classmethod
150 def classCleanup(cls):
151 CleanMakefile()
152
153 # Utilities for testcases
154
155 def check_expression (self, expression, expected_result, use_summary = True):
156 value = self.frame().EvaluateExpression (expression)
157 self.assertTrue(value.IsValid(), expression+"returned a valid value")
158 if self.TraceOn():
159 print value.GetSummary()
160 print value.GetValue()
161 if use_summary:
162 answer = value.GetSummary()
163 else:
164 answer = value.GetValue()
165 report_str = "%s expected: %s got: %s"%(expression, expected_result, answer)
166 self.assertTrue(answer == expected_result, report_str)
167
Sean Callanane17428a2014-10-28 20:23:20 +0000168def ApplyDecoratorsToFunction(func, decorators):
169 tmp = func
170 if type(decorators) == list:
171 for decorator in decorators:
172 tmp = decorator(tmp)
173 elif hasattr(decorators, '__call__'):
174 tmp = decorators(tmp)
175 return tmp
176
177
178def MakeInlineTest(__file, __globals, decorators=None):
Sean Callanan816cb3e2014-10-16 23:15:22 +0000179 # Derive the test name from the current file name
180 file_basename = os.path.basename(__file)
181 InlineTest.mydir = TestBase.compute_mydir(__file)
182
183 test_name, _ = os.path.splitext(file_basename)
184 # Build the test case
185 test = new.classobj(test_name, (InlineTest,), {})
186 test.name = test_name
Sean Callanane17428a2014-10-28 20:23:20 +0000187
188 test.test_with_dsym = ApplyDecoratorsToFunction(test._InlineTest__test_with_dsym, decorators)
189 test.test_with_dwarf = ApplyDecoratorsToFunction(test._InlineTest__test_with_dwarf, decorators)
190
Sean Callanan816cb3e2014-10-16 23:15:22 +0000191 # Add the test case to the globals, and hide InlineTest
192 __globals.update({test_name : test})
Enrico Granataab0e8312014-11-05 21:31:57 +0000193
194 return test
Sean Callanan816cb3e2014-10-16 23:15:22 +0000195