File: TestSwiftStepping.py

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (358 lines) | stat: -rw-r--r-- 13,202 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# TestSwiftStepping.py
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ------------------------------------------------------------------------------
"""
Tests simple swift stepping
"""
import lldb
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbtest as lldbtest
import lldbsuite.test.lldbutil as lldbutil
import os
import platform
import unittest2

class TestSwiftStepping(lldbtest.TestBase):

    mydir = lldbtest.TestBase.compute_mydir(__file__)

    @swiftTest
    @skipIfLinux
    def test_swift_stepping(self):
        """Tests that we can step reliably in swift code."""
        self.build()
        self.do_test()

    def setUp(self):
        lldbtest.TestBase.setUp(self)
        self.main_source = "main.swift"
        self.main_source_spec = lldb.SBFileSpec(self.main_source)
        # If you are running against a debug swift you are going to
        # end up stepping into the stdlib and that will make stepping
        # tests impossible to write.  So avoid that.

        if platform.system() == 'Darwin':
            lib_name = "libswiftCore.dylib"
        else:
            lib_name = "libswiftCore.so"

        self.dbg.HandleCommand(
            "settings set "
            "target.process.thread.step-avoid-libraries {}".format(lib_name))

    def correct_stop_reason(self, thread):
        # We are always just stepping, so that should be the thread stop reason:
        stop_reason = thread.GetStopReason()
        self.assertEqual(stop_reason, lldb.eStopReasonPlanComplete)

    def hit_correct_line(self, thread, pattern, fail_if_wrong=True):
        # print "Check if we got to: ", pattern
        self.correct_stop_reason(thread)
        target_line = lldbtest.line_number(self.main_source, pattern)
        self.assertTrue(
            target_line != 0,
            "Could not find source pattern " + pattern)
        cur_line = thread.frames[0].GetLineEntry().GetLine()
        hit_line = cur_line == target_line
        if fail_if_wrong:
            self.assertTrue(
                hit_line,
                "Stepped to line %d instead of expected %d "
                "with pattern '%s'." % (cur_line, target_line, pattern))
        return hit_line

    def hit_correct_function(self, thread, pattern):
        # print "Check if we got to: ", pattern
        self.correct_stop_reason(thread)
        name = thread.frames[0].GetFunctionName()
        line_entry = thread.frames[0].GetLineEntry()
        desc = lldb.SBStream()
        if line_entry.IsValid():
            line_entry.GetDescription(desc)
        else:
            desc.Print(name)
        self.assertTrue(
            pattern in name,
            "Got to '%s' not the expected function '%s'." % (desc.GetData(), pattern))

    def do_test(self):
        """Tests that we can step reliably in swift code."""
        exe_name = "a.out"
        exe = self.getBuildArtifact(exe_name)

        # Create the target
        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, lldbtest.VALID_TARGET)

        # Set the breakpoints
        breakpoint = target.BreakpointCreateBySourceRegex(
            'Stop here first in main', self.main_source_spec)
        self.assertTrue(
            breakpoint.GetNumLocations() > 0, lldbtest.VALID_BREAKPOINT)

        # Launch the process, and do not stop at the entry point.
        process = target.LaunchSimple(None, None, os.getcwd())

        self.assertTrue(process, lldbtest.PROCESS_IS_VALID)

        # Frame #0 should be at our breakpoint.
        threads = lldbutil.get_threads_stopped_at_breakpoint(
            process, breakpoint)

        self.assertTrue(len(threads) == 1)
        thread = threads[0]
        frame = thread.frames[0]
        self.assertTrue(frame, "Frame 0 is valid.")

        # We are before using an int to set an enum value (which has a
        # toSomeValues function).  So step into should go into the
        # toSomeValues function.

        thread.StepInto()
        self.hit_correct_function(thread, "toSomeValues")

        thread.StepOut()
        self.hit_correct_function(thread, "main")

        thread.StepOver()
        thread.StepOver()

        # That should take me to the equals operator.
        self.hit_correct_line(thread, "Stop here to get into equality")

        thread.StepInto()
        self.hit_correct_function(thread, "==")

        thread.StepOut()
        thread.StepOver()

        self.hit_correct_line(thread, "Step over the if should get here")

        thread.StepOver()
        self.hit_correct_line(thread, "Step over the print should get here.")

        thread.StepOver()
        self.hit_correct_line(thread, "Stop here to step into B constructor.")

        thread.StepInto()
        prologue_at_first_line = self.hit_correct_line(
            thread, "At the first line of B constructor.", False)
        if prologue_at_first_line:
            thread.StepOver()

        self.hit_correct_line(
            thread, "In the B constructor about to call super.")

        # Make sure we can follow super into the parent constructor.
        thread.StepInto()

        prologue_at_first_line = self.hit_correct_line(
            thread, "Here is the A constructor.", False)
        if prologue_at_first_line:
            thread.StepOver()

        self.hit_correct_line(thread, "A init: x assignment.")

        thread.StepOver()
        self.hit_correct_line(thread, "A init: y assignment.")

        thread.StepOver()
        self.hit_correct_line(thread, "A init: end of function.")

        # Now two step outs should take us back where we started from:
        thread.StepOut()
        thread.StepOut()
        name = thread.frames[0].GetFunctionName()
        if "allocating_init" in name:
            thread.StepOut()
        self.hit_correct_line(thread, "Stop here to step into B constructor.")

        thread.StepOver()
        self.hit_correct_line(
            thread, "Stop here to step into call_overridden.")

        # Make sure we get into the overridden call as expected:
        thread.StepInto()
        self.hit_correct_function(thread, "call_overridden")
        stopped_at_func_defn = self.hit_correct_line(
            thread, "call_overridden func def", False)
        if stopped_at_func_defn:
            thread.StepOver()
        thread.StepInto()
        self.hit_correct_function(thread, "ClassB.do_something")

        # Now step out twice to get back to main:
        thread.StepOut()
        self.hit_correct_function(thread, "call_overridden")
        thread.StepOut()
        self.hit_correct_line(
            thread, "Stop here to step into call_overridden.")

        # Two steps should get us to the switch:
        thread.StepOver()
        self.hit_correct_line(thread, "At point initializer.")
        thread.StepOver()
        stopped_at_switch = self.hit_correct_line (thread, "At the beginning of the switch.", False)
        if stopped_at_switch:
            thread.StepOver()

        stopped_at_case = self.hit_correct_line(
            thread, "case (let x, let y) where", False)
        if stopped_at_case:
            thread.StepOver()

        self.hit_correct_line(thread, "First case with a where statement.")
        thread.StepOver()
        self.hit_correct_line(thread, "Second case with a where statement")

        thread.StepInto()
        self.hit_correct_line(
            thread, "return_same gets called in both where statements")

        thread.StepOut()
        self.hit_correct_line(thread, "Second case with a where statement")

        thread.StepOver()
        thread.StepOver()
        self.hit_correct_line(
            thread, "print in second case with where statement.")

        #
        # For some reason, we don't step from the body of the case to
        # the end of the switch, but back to the case: statement, and
        # then directly out of the switch.
        #
        thread.StepOver()
        steps_back_to_case = self.hit_correct_line(
            thread,
            "Sometimes the line table steps to here "
            "after the body of the case.", False)
        if steps_back_to_case:
            self.fail(
                "Stepping past a taken body of a case statement should not "
                "step back to the case statement.")

        if self.hit_correct_line(
                thread,
                "This is the end of the switch statement", False):
            thread.StepOver()
        elif not self.hit_correct_line(
                thread, "Make a version of P that conforms directly", False):
            self.fail(
                "Stepping past the body of the case didn't stop "
                "where expected.")

        self.hit_correct_line(
            thread, "Make a version of P that conforms directly")

        # FIXME: Stepping into constructors is kind of a mess,
        # I'm going to just step over for these tests.
        thread.StepOver()
        self.hit_correct_line(thread, "direct.protocol_func(10)")
        # This tests stepping in through the protocol thunk:
        thread.StepInto()

        stop_at_prologue = self.hit_correct_line(
            thread,
            "We stopped at the protocol_func declaration instead.",
            False)
        if stop_at_prologue:
            thread.StepOver()
        self.hit_correct_line(
            thread, "This is where we will stop in the protocol dispatch")

        # Step out of the protocol functions, one step should get us
        # past any dispatch thunk.
        thread.StepOut()

        # Finish may not get us past the line we were on, since it
        # stops immediately on returning
        # to the caller frame.  If so we will need to step again:
        stop_in_caller_line = self.hit_correct_line(
            thread, "direct.protocol_func(10)", False)
        if stop_in_caller_line:
            thread.StepOver()
        self.hit_correct_line(
            thread, "Make a version of P that conforms through a subclass")

        # This steps into another protocol dispatch.
        thread.StepOver()
        thread.StepInto()
        stop_at_prologue = self.hit_correct_line(
            thread,
            "We stopped at the protocol_func declaration instead.",
            False)
        if stop_at_prologue:
            thread.StepOver()
        self.hit_correct_line(
            thread, "This is where we will stop in the protocol dispatch")

        # Step out of the protocol function, one step out should also
        # get us past any dispatch thunk.
        thread.StepOut()
        stop_on_caller = self.hit_correct_line(thread, "indirect.protocol_func(20)", False)
        stop_at_cd_maker = self.hit_correct_line(thread, "var cd_maker", False)

        # In swift-4.0 U before, one step over is necessary because step out doesn't
        # finish off the line.
        # In swift-4.1 we now step over the line but we also stop on the "var cd_maker"
        # line, which we didn't with swift-4.0.  So we check for either of these.

        if stop_on_caller or stop_at_cd_maker:
            thread.StepOver()

        # Step over the assignment.
        stop_on_partial_apply = self.hit_correct_line(thread, "var cd_maker =", False)
        if stop_on_partial_apply:
            thread.StepOver()

        stop_at_brace = self.hit_correct_line(thread, "Opening brace", False)
        if stop_at_brace:
            thread.StepOver()

        self.hit_correct_line(thread, "doSomethingWithFunction(cd_maker, 10)")

        thread.StepInto()
        stop_in_prologue = self.hit_correct_line(
            thread, "Stopped in doSomethingWithFunctionResult decl.", False)
        if stop_in_prologue:
            thread.StepOver()
        self.hit_correct_line(
            thread, "Calling doSomethingWithFunction with value")
        thread.StepOver()
        self.hit_correct_line(thread, "let result = f(other_value)")

        # Now try stepping into calling a closure, there's several
        # layers of goo to get through:
        thread.StepInto()
        stop_in_prologue = self.hit_correct_line(
            thread, "Step into cd_maker stops at closure decl instead.", False)
        if stop_in_prologue:
            thread.StepOver()

        self.hit_correct_line(thread, "Step into should stop here in closure.")

        # Then make sure we can get back out:
        thread.StepOut()
        # Again, step out may not have completed the source line we
        # stepped in FROM...
        stop_in_caller_line = self.hit_correct_line(
            thread, "let result = f(other_value)", False)
        if stop_in_caller_line:
            thread.StepOver()

        self.hit_correct_line(
            thread, "result.protocol_func(other_value)")

    def tearDown(self):
        self.dbg.HandleCommand(
            "settings clear target.process.thread.step-avoid-libraries")
        super(TestSwiftStepping, self).tearDown()