Skip to content

Commit 1922237

Browse files
mebrianlinmobile-devx-github-bot
authored andcommitted
Make the test stack trace more readable
PiperOrigin-RevId: 735421445
1 parent 7d9fc19 commit 1922237

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed

TestLib/Exception/GREYFailureHandlerHelpers.m

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,64 @@
1616

1717
#import "GREYFailureHandlerHelpers.h"
1818

19+
#include <dlfcn.h>
20+
1921
#import "GREYErrorConstants.h"
2022
#import "GREYFrameworkException.h"
2123
#import "GREYElementHierarchy.h"
2224

25+
static NSString *DemangleSymbol(NSString *symbol) {
26+
static char *(*swiftDemangle)(const char *mangledName, size_t mangledNameLength,
27+
char *outputBuffer, size_t *outputBufferSize, uint32_t flags);
28+
// Exports a function from the Swift stdlib that isn't exposed by default, for demangling Swift
29+
// symbol names.
30+
//
31+
// https://github.com/swiftlang/swift/blob/80050bb455b22cf2eee6fd77816cd41411b975c9/stdlib/public/runtime/Demangle.cpp#L930
32+
static dispatch_once_t onceToken;
33+
dispatch_once(&onceToken, ^{
34+
swiftDemangle = dlsym(RTLD_DEFAULT, "swift_demangle");
35+
});
36+
if (!swiftDemangle) {
37+
return symbol;
38+
}
39+
40+
char *demangledSymbolCString = swiftDemangle(symbol.UTF8String, symbol.length, nil, nil, 0);
41+
if (!demangledSymbolCString) {
42+
return symbol;
43+
}
44+
45+
NSString *demangledSymbol = [NSString stringWithUTF8String:demangledSymbolCString];
46+
free(demangledSymbolCString);
47+
return demangledSymbol;
48+
}
49+
50+
// Trims the stack symbol to make it more readable.
51+
static NSString *TrimStackSymbol(NSString *symbol) {
52+
// The stack symbol is of the form:
53+
// <index> <module> <address> <function> + <offset>
54+
//
55+
// For example:
56+
// 4 EarlGrey 0x0000000100000000 -[EarlGreyImpl handleException:details:] + 123
57+
//
58+
// Note: The implementation relies on how the stack trace is formatted. But since this is strictly
59+
// used to improve the debugging experience by making the stack trace more readable, it is fine if
60+
// any of the steps fails, as long as it fails gracefully (i.e. returns the original symbol
61+
// without crashing).
62+
NSString *functionName =
63+
[symbol stringByReplacingOccurrencesOfString:@".+0x[0-9a-fA-F]+\\s(.+)\\s\\+\\s\\d+$"
64+
withString:@"$1"
65+
options:NSRegularExpressionSearch
66+
range:NSMakeRange(0, symbol.length)];
67+
NSString *demangledFunctionName = DemangleSymbol(functionName);
68+
// Trim the top module name.
69+
NSString *trimmedFunctionName = [demangledFunctionName
70+
stringByReplacingOccurrencesOfString:@"\\w+\\.(\\w+)"
71+
withString:@"$1"
72+
options:NSRegularExpressionSearch
73+
range:NSMakeRange(0, demangledFunctionName.length)];
74+
return [symbol stringByReplacingOccurrencesOfString:functionName withString:trimmedFunctionName];
75+
}
76+
2377
NSString *GREYAppUIHierarchyFromException(GREYFrameworkException *exception, NSString *details) {
2478
NSString *appUIHierarchy = [exception.userInfo valueForKey:kErrorDetailAppUIHierarchyKey];
2579
// For calls from GREYAsserts in the test side, the hierarchy must be populated here. In case an
@@ -47,7 +101,7 @@
47101
if ([stackSymbol containsString:@"__invoking___"]) {
48102
break;
49103
} else if (![stackSymbol containsString:@"-[GREY"] && ![stackSymbol containsString:@" GREY"]) {
50-
[trimmedCallStack addObject:stackSymbol];
104+
[trimmedCallStack addObject:TrimStackSymbol(stackSymbol)];
51105
}
52106
}
53107
// The trimmed stack trace should at least contain the test name and exception-raising method.

0 commit comments

Comments
 (0)