ReflectionUtilities test fix

This commit is contained in:
dragonmacher 2024-03-01 10:09:43 -05:00 committed by Ryan Kurtz
parent c04e02d4e5
commit ff911179b9
2 changed files with 79 additions and 22 deletions

View file

@ -35,7 +35,7 @@ public class ReflectionUtilitiesTest {
@Test @Test
public void testGetClassNameAfter_NoClasses() { public void testGetClassNameAfter_NoClasses() {
String caller = ReflectionUtilities.getClassNameOlderThan(new String[0]); String caller = ReflectionUtilities.getClassNameOlderThan(new Class[0]);
assertThat(caller, is(equalTo(ReflectionUtilitiesTest.class.getName()))); assertThat(caller, is(equalTo(ReflectionUtilitiesTest.class.getName())));
} }

View file

@ -22,6 +22,7 @@ import java.util.Map.Entry;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
public class ReflectionUtilities { public class ReflectionUtilities {
@ -225,11 +226,17 @@ public class ReflectionUtilities {
} }
private static Throwable createThrowableWithStackOlderThan(List<String> patterns) { private static Throwable createThrowableWithStackOlderThan(List<String> patterns) {
return createThrowableWithStackOlderThan(patterns,
StackElementMatcher.CONTAINS_CLASS_OR_METHOD);
}
private static Throwable createThrowableWithStackOlderThan(List<String> patterns,
StackElementMatcher matcher) {
if (patterns.isEmpty()) { if (patterns.isEmpty()) {
// always ignore our class. We get this for free if the client passes in any classes // always ignore our class. We get this for free if the client passes in any classes
patterns = new ArrayList<>(); patterns = new ArrayList<>();
patterns.add(0, ReflectionUtilities.class.getName()); patterns.add(ReflectionUtilities.class.getName());
} }
Throwable t = new Throwable(); Throwable t = new Throwable();
@ -237,8 +244,7 @@ public class ReflectionUtilities {
int lastIgnoreIndex = -1; int lastIgnoreIndex = -1;
for (int i = 0; i < trace.length; i++) { for (int i = 0; i < trace.length; i++) {
StackTraceElement element = trace[i]; StackTraceElement element = trace[i];
String text = element.getClassName() + " " + element.getMethodName(); if (matchesAnyPattern(element, patterns, matcher)) {
if (containsAny(text, patterns)) {
lastIgnoreIndex = i; lastIgnoreIndex = i;
} }
else { else {
@ -267,15 +273,6 @@ public class ReflectionUtilities {
return t; return t;
} }
private static boolean containsAny(String text, List<String> patterns) {
for (String pattern : patterns) {
if (text.contains(pattern)) {
return true;
}
}
return false;
}
/** /**
* Creates a throwable whose stack trace is based upon the current call stack, with any * Creates a throwable whose stack trace is based upon the current call stack, with any
* information coming before, and including, the given classes removed. * information coming before, and including, the given classes removed.
@ -289,7 +286,8 @@ public class ReflectionUtilities {
public static Throwable createThrowableWithStackOlderThan(Class<?>... classes) { public static Throwable createThrowableWithStackOlderThan(Class<?>... classes) {
List<String> patterns = List<String> patterns =
Arrays.stream(classes).map(c -> c.getName()).collect(Collectors.toList()); Arrays.stream(classes).map(c -> c.getName()).collect(Collectors.toList());
return createThrowableWithStackOlderThan(patterns);
return createThrowableWithStackOlderThan(patterns, StackElementMatcher.EXACT_CLASS);
} }
/** /**
@ -309,9 +307,7 @@ public class ReflectionUtilities {
for (int i = 0; i < trace.length; i++) { for (int i = 0; i < trace.length; i++) {
StackTraceElement element = trace[i]; StackTraceElement element = trace[i];
String traceString = element.toString(); boolean matches = matchesAnyPattern(element, pattern);
boolean matches = containsAny(traceString, pattern);
if (foundIt && !matches) { if (foundIt && !matches) {
desiredStartIndex = i; desiredStartIndex = i;
break; break;
@ -346,8 +342,7 @@ public class ReflectionUtilities {
List<StackTraceElement> list = new ArrayList<>(); List<StackTraceElement> list = new ArrayList<>();
for (StackTraceElement element : trace) { for (StackTraceElement element : trace) {
String traceString = element.toString(); if (matchesAnyPattern(element, patterns)) {
if (containsAny(traceString, patterns)) {
continue; continue;
} }
@ -422,9 +417,14 @@ public class ReflectionUtilities {
return t; return t;
} }
private static boolean containsAny(String s, String... patterns) { private static boolean matchesAnyPattern(StackTraceElement element, String... patterns) {
for (String p : patterns) { return matchesAnyPattern(element, List.of(patterns), StackElementMatcher.CONTAINS_ANY);
if (s.contains(p)) { }
private static boolean matchesAnyPattern(StackTraceElement element, List<String> patterns,
StackElementMatcher matcher) {
for (String pattern : patterns) {
if (matcher.matches(element, pattern)) {
return true; return true;
} }
} }
@ -768,4 +768,61 @@ public class ReflectionUtilities {
return ((ParameterizedType) type).getActualTypeArguments(); return ((ParameterizedType) type).getActualTypeArguments();
} }
private static class StackElementMatcher {
static final StackElementMatcher EXACT_CLASS =
new StackElementMatcher(Match.EXACT, Content.CLASS_NAME);
static final StackElementMatcher CONTAINS_CLASS_OR_METHOD =
new StackElementMatcher(Match.CONTAINS, Content.CLASS_AND_METHOD_NAME);
static final StackElementMatcher CONTAINS_ANY =
new StackElementMatcher(Match.CONTAINS, Content.ALL);
static enum Match {
EXACT, CONTAINS;
boolean matches(String input, String pattern) {
switch (this) {
case EXACT:
return input.equals(pattern);
case CONTAINS:
return input.contains(pattern);
default:
throw new AssertException("Missing case type");
}
}
}
static enum Content {
CLASS_NAME, CLASS_AND_METHOD_NAME, ALL;
String convert(StackTraceElement e) {
switch (this) {
case CLASS_NAME:
return e.getClassName();
case CLASS_AND_METHOD_NAME:
return e.getClassName() + ' ' + e.getMethodName();
case ALL:
return e.toString();
default:
throw new AssertException("Missing case type");
}
}
}
private Match matchType;
private Content contentType;
StackElementMatcher(Match matchType, Content contentType) {
this.matchType = matchType;
this.contentType = contentType;
}
boolean matches(StackTraceElement element, String pattern) {
String s = contentType.convert(element);
return matchType.matches(s, pattern);
}
}
} }