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