blob: bb925ef908f5acb7a106ad42bfb814bb50cee5bf [file] [log] [blame]
Zachary Turnerff890da2015-10-19 23:45:41 +00001from __future__ import print_function
Zachary Turnerc1b7cd72015-11-05 19:22:28 +00002from __future__ import absolute_import
Zachary Turnerff890da2015-10-19 23:45:41 +00003
Zachary Turnerc1b7cd72015-11-05 19:22:28 +00004# System modules
Sean Callanan816cb3e2014-10-16 23:15:22 +00005import os
Sean Callanan816cb3e2014-10-16 23:15:22 +00006
Zachary Turnerc1b7cd72015-11-05 19:22:28 +00007# Third-party modules
8
9# LLDB modules
10import lldb
11from .lldbtest import *
Todd Fiala94eb0102016-05-26 13:57:03 +000012from . import configuration
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000013from . import lldbutil
Zachary Turner9a1a2942016-02-04 23:04:17 +000014from .decorators import *
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000015
Kate Stoneb9c1b512016-09-06 20:57:50 +000016
Sean Callanan816cb3e2014-10-16 23:15:22 +000017def source_type(filename):
18 _, extension = os.path.splitext(filename)
19 return {
Kate Stoneb9c1b512016-09-06 20:57:50 +000020 '.c': 'C_SOURCES',
21 '.cpp': 'CXX_SOURCES',
22 '.cxx': 'CXX_SOURCES',
23 '.cc': 'CXX_SOURCES',
24 '.m': 'OBJC_SOURCES',
25 '.mm': 'OBJCXX_SOURCES'
Sean Callanan816cb3e2014-10-16 23:15:22 +000026 }.get(extension, None)
27
Todd Fialad9be7532016-01-06 19:16:45 +000028
Sean Callanan816cb3e2014-10-16 23:15:22 +000029class CommandParser:
Kate Stoneb9c1b512016-09-06 20:57:50 +000030
Sean Callanan816cb3e2014-10-16 23:15:22 +000031 def __init__(self):
32 self.breakpoints = []
33
34 def parse_one_command(self, line):
35 parts = line.split('//%')
Sean Callanand950fa72014-10-17 00:39:37 +000036
37 command = None
38 new_breakpoint = True
39
40 if len(parts) == 2:
Todd Fialad9be7532016-01-06 19:16:45 +000041 command = parts[1].strip() # take off whitespace
Sean Callanand950fa72014-10-17 00:39:37 +000042 new_breakpoint = parts[0].strip() != ""
43
44 return (command, new_breakpoint)
Sean Callanan816cb3e2014-10-16 23:15:22 +000045
46 def parse_source_files(self, source_files):
47 for source_file in source_files:
48 file_handle = open(source_file)
49 lines = file_handle.readlines()
50 line_number = 0
Kate Stoneb9c1b512016-09-06 20:57:50 +000051 # non-NULL means we're looking through whitespace to find
52 # additional commands
53 current_breakpoint = None
Sean Callanan816cb3e2014-10-16 23:15:22 +000054 for line in lines:
Kate Stoneb9c1b512016-09-06 20:57:50 +000055 line_number = line_number + 1 # 1-based, so we do this first
Sean Callanand950fa72014-10-17 00:39:37 +000056 (command, new_breakpoint) = self.parse_one_command(line)
57
58 if new_breakpoint:
59 current_breakpoint = None
60
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 if command is not None:
62 if current_breakpoint is None:
Sean Callanand950fa72014-10-17 00:39:37 +000063 current_breakpoint = {}
64 current_breakpoint['file_name'] = source_file
65 current_breakpoint['line_number'] = line_number
66 current_breakpoint['command'] = command
67 self.breakpoints.append(current_breakpoint)
68 else:
Kate Stoneb9c1b512016-09-06 20:57:50 +000069 current_breakpoint['command'] = current_breakpoint[
70 'command'] + "\n" + command
Sean Callanan816cb3e2014-10-16 23:15:22 +000071
72 def set_breakpoints(self, target):
73 for breakpoint in self.breakpoints:
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 breakpoint['breakpoint'] = target.BreakpointCreateByLocation(
75 breakpoint['file_name'], breakpoint['line_number'])
Sean Callanan816cb3e2014-10-16 23:15:22 +000076
77 def handle_breakpoint(self, test, breakpoint_id):
78 for breakpoint in self.breakpoints:
79 if breakpoint['breakpoint'].GetID() == breakpoint_id:
80 test.execute_user_command(breakpoint['command'])
81 return
82
Kate Stoneb9c1b512016-09-06 20:57:50 +000083
Sean Callanan816cb3e2014-10-16 23:15:22 +000084class InlineTest(TestBase):
85 # Internal implementation
86
Greg Clayton70995582015-01-07 22:25:50 +000087 def BuildMakefile(self):
Adrian Prantl5ec76fe2018-01-30 18:29:16 +000088 makefilePath = self.getBuildArtifact("Makefile")
89 if os.path.exists(makefilePath):
Pavel Labathf0f62d82016-06-07 21:29:46 +000090 return
91
Greg Clayton70995582015-01-07 22:25:50 +000092 categories = {}
93
Adrian Prantl5ec76fe2018-01-30 18:29:16 +000094 for f in os.listdir(self.getSourceDir()):
Greg Clayton70995582015-01-07 22:25:50 +000095 t = source_type(f)
96 if t:
Zachary Turner606e1e32015-10-23 17:53:51 +000097 if t in list(categories.keys()):
Greg Clayton70995582015-01-07 22:25:50 +000098 categories[t].append(f)
99 else:
100 categories[t] = [f]
101
Adrian Prantl5ec76fe2018-01-30 18:29:16 +0000102 makefile = open(makefilePath, 'w+')
Greg Clayton70995582015-01-07 22:25:50 +0000103
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104 level = os.sep.join(
105 [".."] * len(self.mydir.split(os.sep))) + os.sep + "make"
Greg Clayton70995582015-01-07 22:25:50 +0000106
107 makefile.write("LEVEL = " + level + "\n")
108
Zachary Turner606e1e32015-10-23 17:53:51 +0000109 for t in list(categories.keys()):
Greg Clayton70995582015-01-07 22:25:50 +0000110 line = t + " := " + " ".join(categories[t])
111 makefile.write(line + "\n")
112
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 if ('OBJCXX_SOURCES' in list(categories.keys())) or (
114 'OBJC_SOURCES' in list(categories.keys())):
115 makefile.write(
116 "LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n")
Greg Clayton70995582015-01-07 22:25:50 +0000117
Zachary Turner606e1e32015-10-23 17:53:51 +0000118 if ('CXX_SOURCES' in list(categories.keys())):
Greg Clayton70995582015-01-07 22:25:50 +0000119 makefile.write("CXXFLAGS += -std=c++11\n")
120
Pavel Labathf0f62d82016-06-07 21:29:46 +0000121 makefile.write("include $(LEVEL)/Makefile.rules\n")
Sean Callananbca81c52016-01-26 01:15:57 +0000122 makefile.write("\ncleanup:\n\trm -f Makefile *.d\n\n")
Greg Clayton70995582015-01-07 22:25:50 +0000123 makefile.flush()
124 makefile.close()
125
Pavel Labath66377382018-06-05 10:58:44 +0000126 def _test(self):
Greg Clayton70995582015-01-07 22:25:50 +0000127 self.BuildMakefile()
Adrian Prantl5ec76fe2018-01-30 18:29:16 +0000128 self.build()
Sean Callanan816cb3e2014-10-16 23:15:22 +0000129 self.do_test()
Todd Fiala94eb0102016-05-26 13:57:03 +0000130
Sean Callanan816cb3e2014-10-16 23:15:22 +0000131 def execute_user_command(self, __command):
Zachary Turner5821f792015-11-06 21:37:21 +0000132 exec(__command, globals(), locals())
Sean Callanan816cb3e2014-10-16 23:15:22 +0000133
134 def do_test(self):
Adrian Prantl595048f2018-01-19 23:24:35 +0000135 exe = self.getBuildArtifact("a.out")
Adrian Prantl5ec76fe2018-01-30 18:29:16 +0000136 source_files = [f for f in os.listdir(self.getSourceDir())
137 if source_type(f)]
Sean Callanan816cb3e2014-10-16 23:15:22 +0000138 target = self.dbg.CreateTarget(exe)
139
140 parser = CommandParser()
141 parser.parse_source_files(source_files)
142 parser.set_breakpoints(target)
143
Pavel Labath9bdd03f2018-02-27 22:45:49 +0000144 process = target.LaunchSimple(None, None, self.get_process_working_directory())
Adrian Prantl87a000d2018-02-26 22:40:20 +0000145 hit_breakpoints = 0
Sean Callanan816cb3e2014-10-16 23:15:22 +0000146
147 while lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint):
Adrian Prantl87a000d2018-02-26 22:40:20 +0000148 hit_breakpoints += 1
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 thread = lldbutil.get_stopped_thread(
150 process, lldb.eStopReasonBreakpoint)
151 breakpoint_id = thread.GetStopReasonDataAtIndex(0)
Sean Callanan816cb3e2014-10-16 23:15:22 +0000152 parser.handle_breakpoint(self, breakpoint_id)
153 process.Continue()
154
Adrian Prantl87a000d2018-02-26 22:40:20 +0000155 self.assertTrue(hit_breakpoints > 0,
156 "inline test did not hit a single breakpoint")
157 # Either the process exited or the stepping plan is complete.
158 self.assertTrue(process.GetState() in [lldb.eStateStopped,
159 lldb.eStateExited],
160 PROCESS_EXITED)
161
Sean Callanan816cb3e2014-10-16 23:15:22 +0000162 # Utilities for testcases
163
Kate Stoneb9c1b512016-09-06 20:57:50 +0000164 def check_expression(self, expression, expected_result, use_summary=True):
165 value = self.frame().EvaluateExpression(expression)
166 self.assertTrue(value.IsValid(), expression + "returned a valid value")
Sean Callanan816cb3e2014-10-16 23:15:22 +0000167 if self.TraceOn():
Zachary Turnerff890da2015-10-19 23:45:41 +0000168 print(value.GetSummary())
169 print(value.GetValue())
Sean Callanan816cb3e2014-10-16 23:15:22 +0000170 if use_summary:
171 answer = value.GetSummary()
172 else:
173 answer = value.GetValue()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000174 report_str = "%s expected: %s got: %s" % (
175 expression, expected_result, answer)
Sean Callanan816cb3e2014-10-16 23:15:22 +0000176 self.assertTrue(answer == expected_result, report_str)
177
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178
Sean Callanane17428a2014-10-28 20:23:20 +0000179def ApplyDecoratorsToFunction(func, decorators):
180 tmp = func
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181 if isinstance(decorators, list):
Sean Callanane17428a2014-10-28 20:23:20 +0000182 for decorator in decorators:
183 tmp = decorator(tmp)
184 elif hasattr(decorators, '__call__'):
185 tmp = decorators(tmp)
186 return tmp
Adrian McCarthy3f998102016-05-04 23:32:35 +0000187
Sean Callanane17428a2014-10-28 20:23:20 +0000188
189def MakeInlineTest(__file, __globals, decorators=None):
Todd Fialadad52ce2016-04-18 20:26:56 +0000190 # Adjust the filename if it ends in .pyc. We want filenames to
191 # reflect the source python file, not the compiled variant.
192 if __file is not None and __file.endswith(".pyc"):
193 # Strip the trailing "c"
194 __file = __file[0:-1]
195
Sean Callanan816cb3e2014-10-16 23:15:22 +0000196 # Derive the test name from the current file name
197 file_basename = os.path.basename(__file)
198 InlineTest.mydir = TestBase.compute_mydir(__file)
199
200 test_name, _ = os.path.splitext(file_basename)
Sean Callanane17428a2014-10-28 20:23:20 +0000201
Pavel Labath66377382018-06-05 10:58:44 +0000202 test_func = ApplyDecoratorsToFunction(InlineTest._test, decorators)
203 # Build the test case
204 test_class = type(test_name, (InlineTest,), dict(test=test_func, name=test_name))
Sean Callanane17428a2014-10-28 20:23:20 +0000205
Sean Callanan816cb3e2014-10-16 23:15:22 +0000206 # Add the test case to the globals, and hide InlineTest
Pavel Labath66377382018-06-05 10:58:44 +0000207 __globals.update({test_name: test_class})
Todd Fiala5bdbef642015-12-22 17:14:47 +0000208
Todd Fialadad52ce2016-04-18 20:26:56 +0000209 # Keep track of the original test filename so we report it
210 # correctly in test results.
Pavel Labath66377382018-06-05 10:58:44 +0000211 test_class.test_filename = __file
212 return test_class