Skip to content

Commit 35b0726

Browse files
committed
Add support for enum value comparison
enum value is expressed as string with either fully qualified name, simple name with enum class of just the enum value.
1 parent 594de2e commit 35b0726

3 files changed

Lines changed: 101 additions & 1 deletion

File tree

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/ComparisonOperator.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,52 @@ public Boolean apply(Value<?> left, Value<?> right) {
2121
}
2222
return compare(leftNumber, rightNumber) == 0;
2323
}
24+
if (left.getValue() instanceof Enum || right.getValue() instanceof Enum) {
25+
return applyEqualityForEnum(left, right);
26+
}
2427
if (left.getValue().getClass() == right.getValue().getClass()) {
2528
return Objects.equals(left.getValue(), right.getValue());
2629
}
2730
return Boolean.FALSE;
2831
}
32+
33+
private Boolean applyEqualityForEnum(Value<?> left, Value<?> right) {
34+
if (left.getValue() instanceof Enum && right instanceof StringValue) {
35+
return doApplyEqualityForEnum(left, right);
36+
}
37+
if (left instanceof StringValue && right.getValue() instanceof Enum) {
38+
return doApplyEqualityForEnum(right, left);
39+
}
40+
throw new EvaluationException(
41+
"Equality operator is not supported for the given types: "
42+
+ left.getValue().getClass().getName()
43+
+ " and "
44+
+ right.getValue().getClass().getName(),
45+
null);
46+
}
47+
48+
private Boolean doApplyEqualityForEnum(Value<?> enumExpr, Value<?> enumValueExpr) {
49+
Enum<?> enumValue = (Enum<?>) enumExpr.getValue();
50+
String enumValueStr = (String) enumValueExpr.getValue();
51+
Class<? extends Enum> enumClass = enumValue.getClass();
52+
Enum[] enumConstants = enumClass.getEnumConstants();
53+
for (Enum<?> enumConstant : enumConstants) {
54+
// Check if string constant as value expression matches for enum constant
55+
// the endsWith allow to match either:
56+
// - the full enum constant name (com.datadog.debugger.MyEnum.ONE)
57+
// - the simple name with enum class name (MyEnum.ONE)
58+
// - the simple name (ONE)
59+
// The second check against enumValue is to ensure the instance filtered based on the
60+
// name is still correct because the name can partially match (CLOSE in OPENCLOSE)
61+
// with an enum defined like (OPEN, CLOSE, OPENCLOSE)
62+
if (enumValueStr.endsWith(enumConstant.name())) {
63+
if (enumValue.equals(enumConstant)) {
64+
return Boolean.TRUE;
65+
}
66+
}
67+
}
68+
return Boolean.FALSE;
69+
}
2970
},
3071
GE(">=") {
3172
@Override

dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/ComparisonExpressionTest.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.datadog.debugger.el.values.StringValue;
1717
import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver;
1818
import java.math.BigDecimal;
19+
import java.nio.file.StandardOpenOption;
1920
import java.util.ArrayList;
2021
import java.util.Random;
2122
import java.util.stream.Stream;
@@ -164,7 +165,37 @@ private static Stream<Arguments> expressions() {
164165
new StringValue("java.lang.Double"),
165166
INSTANCEOF,
166167
true,
167-
"1.0 instanceof \"java.lang.Double\""));
168+
"1.0 instanceof \"java.lang.Double\""),
169+
Arguments.of(
170+
new ObjectValue(StandardOpenOption.READ),
171+
new StringValue("READ"),
172+
EQ,
173+
true,
174+
"java.nio.file.StandardOpenOption == \"READ\""),
175+
Arguments.of(
176+
new ObjectValue(StandardOpenOption.READ),
177+
new StringValue("StandardOpenOption.READ"),
178+
EQ,
179+
true,
180+
"java.nio.file.StandardOpenOption == \"StandardOpenOption.READ\""),
181+
Arguments.of(
182+
new ObjectValue(StandardOpenOption.READ),
183+
new StringValue("java.nio.file.StandardOpenOption.READ"),
184+
EQ,
185+
true,
186+
"java.nio.file.StandardOpenOption == \"java.nio.file.StandardOpenOption.READ\""),
187+
Arguments.of(
188+
new ObjectValue(StandardOpenOption.CREATE),
189+
new StringValue("READ"),
190+
EQ,
191+
false,
192+
"java.nio.file.StandardOpenOption == \"READ\""),
193+
Arguments.of(
194+
new StringValue("READ"),
195+
new ObjectValue(StandardOpenOption.READ),
196+
EQ,
197+
true,
198+
"\"READ\" == java.nio.file.StandardOpenOption"));
168199
}
169200

170201
@ParameterizedTest

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,34 @@ public void enumValues() throws IOException, URISyntaxException {
17761776
"TWO");
17771777
}
17781778

1779+
@Test
1780+
public void enumCondition() throws IOException, URISyntaxException {
1781+
final String CLASS_NAME = "com.datadog.debugger.CapturedSnapshot23";
1782+
LogProbe probe =
1783+
createProbeBuilder(PROBE_ID, CLASS_NAME, "convert", null)
1784+
.evaluateAt(MethodLocation.EXIT)
1785+
.when(
1786+
new ProbeCondition(
1787+
DSL.when(
1788+
DSL.and(
1789+
DSL.eq(DSL.ref("@return"), DSL.value("TWO")),
1790+
DSL.eq(DSL.ref("@return"), DSL.value("MyEnum.TWO")),
1791+
DSL.eq(
1792+
DSL.ref("@return"),
1793+
DSL.value("com.datadog.debugger.CapturedSnapshot23$MyEnum.TWO")))),
1794+
"@return == 'TWO' && @return == 'MyEnum.TWO' && @return == 'com.datadog.debugger.CapturedSnapshot23$MyEnum.TWO'"))
1795+
.build();
1796+
TestSnapshotListener listener = installProbes(CLASS_NAME, probe);
1797+
Class<?> testClass = compileAndLoadClass(CLASS_NAME);
1798+
int result = Reflect.onClass(testClass).call("main", "2").get();
1799+
assertEquals(2, result);
1800+
Snapshot snapshot = assertOneSnapshot(listener);
1801+
assertCaptureReturnValue(
1802+
snapshot.getCaptures().getReturn(),
1803+
"com.datadog.debugger.CapturedSnapshot23$MyEnum",
1804+
"TWO");
1805+
}
1806+
17791807
@Test
17801808
public void recursiveCapture() throws IOException, URISyntaxException {
17811809
final String CLASS_NAME = "com.datadog.debugger.CapturedSnapshot24";

0 commit comments

Comments
 (0)