1"""
2Use lldb Python API to verify that expression evaluation for property references uses the correct getters and setters
3"""
4
5import os, time
6import re
7import unittest2
8import lldb, lldbutil
9from lldbtest import *
10
11class ObjCPropertyTestCase(TestBase):
12
13    mydir = os.path.join("lang", "objc", "objc-property")
14
15    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
16    @python_api_test
17    @dsym_test
18    def test_objc_properties_with_dsym(self):
19        """Test that expr uses the correct property getters and setters"""
20        if self.getArchitecture() == 'i386':
21            self.skipTest("requires modern objc runtime")
22        self.buildDsym()
23        self.do_test_properties()
24
25    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
26    @python_api_test
27    @dwarf_test
28    def test_objc_properties_with_dwarf(self):
29        """Test that expr uses the correct property getters and setters"""
30        if self.getArchitecture() == 'i386':
31            self.skipTest("requires modern objc runtime")
32        self.buildDwarf()
33        self.do_test_properties()
34
35    def setUp(self):
36        # Call super's setUp().
37        TestBase.setUp(self)
38
39        # Find the line number to break for main.c.
40
41        self.source_name = 'main.m'
42
43    def run_to_main (self):
44        """Test that expr uses the correct property getters and setters"""
45        exe = os.path.join(os.getcwd(), "a.out")
46
47        # Create a target from the debugger.
48
49        target = self.dbg.CreateTarget (exe)
50        self.assertTrue(target, VALID_TARGET)
51
52        # Set up our breakpoints:
53
54        main_bkpt = target.BreakpointCreateBySourceRegex ("Set a breakpoint here.", lldb.SBFileSpec (self.source_name))
55        self.assertTrue(main_bkpt and
56                        main_bkpt.GetNumLocations() == 1,
57                        VALID_BREAKPOINT)
58
59        # Now launch the process, and do not stop at the entry point.
60        process = target.LaunchSimple (None, None, os.getcwd())
61
62        self.assertTrue(process.GetState() == lldb.eStateStopped,
63                        PROCESS_STOPPED)
64
65        threads = lldbutil.get_threads_stopped_at_breakpoint (process, main_bkpt)
66        self.assertTrue (len(threads) == 1)
67        thread = threads[0]
68        return thread
69
70    def do_test_properties (self):
71
72        thread = self.run_to_main()
73
74        frame = thread.GetFrameAtIndex(0)
75
76        mine = frame.FindVariable ("mine")
77        self.assertTrue (mine.IsValid())
78        access_count = mine.GetChildMemberWithName ("_access_count")
79        self.assertTrue (access_count.IsValid())
80        start_access_count = access_count.GetValueAsUnsigned (123456)
81        self.assertTrue (start_access_count != 123456)
82
83        #
84        # The first set of tests test calling the getter & setter of
85        # a property that actually only has a getter & setter and no
86        # @property.
87        #
88        nonexistant_value = frame.EvaluateExpression("mine.nonexistantInt", False)
89        nonexistant_error = nonexistant_value.GetError()
90        self.assertTrue (nonexistant_error.Success())
91        nonexistant_int = nonexistant_value.GetValueAsUnsigned (123456)
92        self.assertTrue (nonexistant_int == 6)
93
94        # Calling the getter function would up the access count, so make sure that happened.
95
96        new_access_count = access_count.GetValueAsUnsigned (123456)
97        self.assertTrue (new_access_count - start_access_count == 1)
98        start_access_count = new_access_count
99
100        #
101        # Now call the setter, then make sure that
102        nonexistant_change = frame.EvaluateExpression("mine.nonexistantInt = 10", False)
103        nonexistant_error = nonexistant_change.GetError()
104        self.assertTrue (nonexistant_error.Success())
105
106        # Calling the setter function would up the access count, so make sure that happened.
107
108        new_access_count = access_count.GetValueAsUnsigned (123456)
109        self.assertTrue (new_access_count - start_access_count == 1)
110        start_access_count = new_access_count
111
112        #
113        # Now we call the getter of a property that is backed by an ivar,
114        # make sure it works and that we actually update the backing ivar.
115        #
116
117        backed_value = frame.EvaluateExpression("mine.backedInt", False)
118        backed_error = backed_value.GetError()
119        self.assertTrue (backed_error.Success())
120        backing_value = mine.GetChildMemberWithName ("_backedInt")
121        self.assertTrue (backing_value.IsValid())
122        self.assertTrue (backed_value.GetValueAsUnsigned (12345) == backing_value.GetValueAsUnsigned(23456))
123
124        unbacked_value = frame.EvaluateExpression("mine.unbackedInt", False)
125        unbacked_error = unbacked_value.GetError()
126        self.assertTrue (unbacked_error.Success())
127
128        idWithProtocol_value = frame.EvaluateExpression("mine.idWithProtocol", False)
129        idWithProtocol_error = idWithProtocol_value.GetError()
130        self.assertTrue (idWithProtocol_error.Success())
131        self.assertTrue (idWithProtocol_value.GetTypeName() == "id")
132
133if __name__ == '__main__':
134    import atexit
135    lldb.SBDebugger.Initialize()
136    atexit.register(lambda: lldb.SBDebugger.Terminate())
137    unittest2.main()
138