10 from .lldbtest
import *
11 from . import configuration
12 from . import lldbutil
13 from .decorators
import *
16 def source_type(filename
):
17 _
, extension
= os
.path
.splitext(filename
)
20 ".cpp": "CXX_SOURCES",
21 ".cxx": "CXX_SOURCES",
24 ".mm": "OBJCXX_SOURCES",
25 }.get(extension
, None)
32 def parse_one_command(self
, line
):
33 parts
= line
.split("//%")
39 command
= parts
[1].rstrip()
40 new_breakpoint
= parts
[0].strip() != ""
42 return (command
, new_breakpoint
)
44 def parse_source_files(self
, source_files
):
45 for source_file
in source_files
:
46 file_handle
= io
.open(source_file
, encoding
="utf-8")
47 lines
= file_handle
.readlines()
49 # non-NULL means we're looking through whitespace to find
51 current_breakpoint
= None
53 line_number
= line_number
+ 1 # 1-based, so we do this first
54 (command
, new_breakpoint
) = self
.parse_one_command(line
)
57 current_breakpoint
= None
59 if command
is not None:
60 if current_breakpoint
is None:
61 current_breakpoint
= {}
62 current_breakpoint
["file_name"] = source_file
63 current_breakpoint
["line_number"] = line_number
64 current_breakpoint
["command"] = command
65 self
.breakpoints
.append(current_breakpoint
)
67 current_breakpoint
["command"] = (
68 current_breakpoint
["command"] + "\n" + command
70 for bkpt
in self
.breakpoints
:
71 bkpt
["command"] = textwrap
.dedent(bkpt
["command"])
73 def set_breakpoints(self
, target
):
74 for breakpoint
in self
.breakpoints
:
75 breakpoint
["breakpoint"] = target
.BreakpointCreateByLocation(
76 breakpoint
["file_name"], breakpoint
["line_number"]
79 def handle_breakpoint(self
, test
, breakpoint_id
):
80 for breakpoint
in self
.breakpoints
:
81 if breakpoint
["breakpoint"].GetID() == breakpoint_id
:
82 test
.execute_user_command(breakpoint
["command"])
86 class InlineTest(TestBase
):
87 def getBuildDirBasename(self
):
88 return self
.__class
__.__name
__ + "." + self
.testMethodName
90 def BuildMakefile(self
):
91 makefilePath
= self
.getBuildArtifact("Makefile")
92 if os
.path
.exists(makefilePath
):
96 for f
in os
.listdir(self
.getSourceDir()):
99 if t
in list(categories
.keys()):
100 categories
[t
].append(f
)
104 with
open(makefilePath
, "w+") as makefile
:
105 for t
in list(categories
.keys()):
106 line
= t
+ " := " + " ".join(categories
[t
])
107 makefile
.write(line
+ "\n")
109 if ("OBJCXX_SOURCES" in list(categories
.keys())) or (
110 "OBJC_SOURCES" in list(categories
.keys())
112 makefile
.write("LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n")
114 if "CXX_SOURCES" in list(categories
.keys()):
115 makefile
.write("CXXFLAGS += -std=c++11\n")
117 makefile
.write("include Makefile.rules\n")
121 self
.build(dictionary
=self
._build
_dict
)
124 def execute_user_command(self
, __command
):
125 exec(__command
, globals(), locals())
127 def _get_breakpoint_ids(self
, thread
):
129 for i
in range(0, thread
.GetStopReasonDataCount(), 2):
130 ids
.add(thread
.GetStopReasonDataAtIndex(i
))
131 self
.assertGreater(len(ids
), 0)
135 exe
= self
.getBuildArtifact("a.out")
136 source_files
= [f
for f
in os
.listdir(self
.getSourceDir()) if source_type(f
)]
137 target
= self
.dbg
.CreateTarget(exe
)
139 parser
= CommandParser()
140 parser
.parse_source_files(source_files
)
141 parser
.set_breakpoints(target
)
143 process
= target
.LaunchSimple(None, None, self
.get_process_working_directory())
144 self
.assertIsNotNone(process
, PROCESS_IS_VALID
)
148 while lldbutil
.get_stopped_thread(process
, lldb
.eStopReasonBreakpoint
):
150 thread
= lldbutil
.get_stopped_thread(process
, lldb
.eStopReasonBreakpoint
)
151 for bp_id
in self
._get
_breakpoint
_ids
(thread
):
152 parser
.handle_breakpoint(self
, bp_id
)
156 hit_breakpoints
> 0, "inline test did not hit a single breakpoint"
158 # Either the process exited or the stepping plan is complete.
160 process
.GetState() in [lldb
.eStateStopped
, lldb
.eStateExited
],
164 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")
168 print(value
.GetSummary())
169 print(value
.GetValue())
171 answer
= value
.GetSummary()
173 answer
= value
.GetValue()
174 report_str
= "%s expected: %s got: %s" % (expression
, expected_result
, answer
)
175 self
.assertTrue(answer
== expected_result
, report_str
)
178 def ApplyDecoratorsToFunction(func
, decorators
):
180 if isinstance(decorators
, list):
181 for decorator
in decorators
:
183 elif hasattr(decorators
, "__call__"):
184 tmp
= decorators(tmp
)
188 def MakeInlineTest(__file
, __globals
, decorators
=None, name
=None, build_dict
=None):
189 # Adjust the filename if it ends in .pyc. We want filenames to
190 # reflect the source python file, not the compiled variant.
191 if __file
is not None and __file
.endswith(".pyc"):
192 # Strip the trailing "c"
193 __file
= __file
[0:-1]
196 # Derive the test name from the current file name
197 file_basename
= os
.path
.basename(__file
)
198 name
, _
= os
.path
.splitext(file_basename
)
200 test_func
= ApplyDecoratorsToFunction(InlineTest
._test
, decorators
)
201 # Build the test case
203 name
, (InlineTest
,), dict(test
=test_func
, name
=name
, _build_dict
=build_dict
)
206 # Add the test case to the globals, and hide InlineTest
207 __globals
.update({name
: test_class
})
209 # Keep track of the original test filename so we report it
210 # correctly in test results.
211 test_class
.test_filename
= __file
212 test_class
.mydir
= TestBase
.compute_mydir(__file
)