Index: packages/Python/lldbsuite/test/functionalities/mtc/simple/Makefile =================================================================== --- packages/Python/lldbsuite/test/functionalities/mtc/simple/Makefile +++ packages/Python/lldbsuite/test/functionalities/mtc/simple/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +OBJC_SOURCES := main.m +LDFLAGS = $(CFLAGS) -lobjc -framework Foundation -framework AppKit + +include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/functionalities/mtc/simple/TestMTCSimple.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/mtc/simple/TestMTCSimple.py +++ packages/Python/lldbsuite/test/functionalities/mtc/simple/TestMTCSimple.py @@ -0,0 +1,65 @@ +""" +Tests basic Main Thread Checker support (detecting a main-thread-only violation). +""" + +import os +import time +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil +import json + + +class MTCSimpleTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessDarwin + def test(self): + mtc_dylib_path = "" + with os.popen('xcode-select -p') as output: + xcode_developer_path = output.read().strip() + mtc_dylib_path = '%s/usr/lib/libMainThreadChecker.dylib' % xcode_developer_path + if not os.path.isfile(mtc_dylib_path): + mtc_dylib_path = "" + + if mtc_dylib_path == "": + self.skipTest("This test requires libMainThreadChecker.dylib.") + return + + self.mtc_dylib_path = mtc_dylib_path + + self.build() + self.mtc_tests() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + def mtc_tests(self): + # Load the test + exe = os.path.join(os.getcwd(), "a.out") + self.expect("file " + exe, patterns=["Current executable set to .*a.out"]) + + self.runCmd("env DYLD_INSERT_LIBRARIES=%s" % self.mtc_dylib_path) + self.runCmd("run") + + process = self.dbg.GetSelectedTarget().process + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + + self.expect("thread info", substrs=['stop reason = -[NSView superview] must be called from main thread only']) + + self.expect( + "thread info -s", + substrs=["instrumentation_class", "api_name", "class_name", "selector", "description"]) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonInstrumentation) + output_lines = self.res.GetOutput().split('\n') + json_line = '\n'.join(output_lines[2:]) + data = json.loads(json_line) + self.assertEqual(data["instrumentation_class"], "MainThreadChecker") + self.assertEqual(data["api_name"], "-[NSView superview]") + self.assertEqual(data["class_name"], "NSView") + self.assertEqual(data["selector"], "superview") + self.assertEqual(data["description"], "-[NSView superview] must be called from main thread only") Index: packages/Python/lldbsuite/test/functionalities/mtc/simple/main.m =================================================================== --- packages/Python/lldbsuite/test/functionalities/mtc/simple/main.m +++ packages/Python/lldbsuite/test/functionalities/mtc/simple/main.m @@ -0,0 +1,15 @@ +#import +#import + +int main() { + NSView *view = [[NSView alloc] init]; + dispatch_group_t g = dispatch_group_create(); + dispatch_group_enter(g); + [NSThread detachNewThreadWithBlock:^{ + @autoreleasepool { + [view superview]; + } + dispatch_group_leave(g); + }]; + dispatch_group_wait(g, DISPATCH_TIME_FOREVER); +}