diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/CollectionExpressionHelper.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/CollectionExpressionHelper.java new file mode 100644 index 00000000000..c811c82fa73 --- /dev/null +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/CollectionExpressionHelper.java @@ -0,0 +1,64 @@ +package com.datadog.debugger.el.expressions; + +import static com.datadog.debugger.el.PrettyPrintVisitor.print; + +import com.datadog.debugger.el.EvaluationException; +import com.datadog.debugger.el.Expression; +import com.datadog.debugger.el.Value; +import com.datadog.debugger.el.values.ListValue; +import com.datadog.debugger.el.values.MapValue; +import com.datadog.debugger.el.values.SetValue; +import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; +import datadog.trace.bootstrap.debugger.util.WellKnownClasses; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class CollectionExpressionHelper { + public static void checkSupportedMap(MapValue map, Expression expression) { + Map mapHolder = (Map) map.getMapHolder(); + if (!WellKnownClasses.isSafe(mapHolder)) { + throw new EvaluationException( + "Unsupported Map class: " + mapHolder.getClass().getTypeName(), print(expression)); + } + } + + public static void checkSupportedList(ListValue collection, Expression expression) { + Object holder = collection.getValue(); + if (holder instanceof List) { + if (!WellKnownClasses.isSafe((List) holder)) { + throw new EvaluationException( + "Unsupported List class: " + holder.getClass().getTypeName(), print(expression)); + } + } + } + + public static Value evaluateTargetCollection( + ValueExpression collectionTarget, + Expression expression, + ValueReferenceResolver valueRefResolver) { + if (collectionTarget == null) { + throw new EvaluationException( + "Cannot evaluate the expression for null value", print(expression)); + } + Value value = collectionTarget.evaluate(valueRefResolver); + if (value.isUndefined()) { + throw new EvaluationException( + "Cannot evaluate the expression for undefined value", print(expression)); + } + if (value.isNull()) { + throw new EvaluationException( + "Cannot evaluate the expression for null value", print(expression)); + } + return value; + } + + public static Set checkSupportedSet(SetValue set, Expression expression) { + Set setHolder = (Set) set.getSetHolder(); + if (!WellKnownClasses.isSafe(setHolder)) { + throw new EvaluationException( + "Unsupported Set class: " + setHolder.getClass().getTypeName(), print(expression)); + } + return setHolder; + } +} diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/FilterCollectionExpression.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/FilterCollectionExpression.java index df0ff96906e..d9534f068b5 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/FilterCollectionExpression.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/FilterCollectionExpression.java @@ -1,17 +1,27 @@ package com.datadog.debugger.el.expressions; +import static com.datadog.debugger.el.PrettyPrintVisitor.print; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedList; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedMap; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedSet; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.evaluateTargetCollection; + +import com.datadog.debugger.el.EvaluationException; import com.datadog.debugger.el.Value; import com.datadog.debugger.el.Visitor; import com.datadog.debugger.el.values.CollectionValue; import com.datadog.debugger.el.values.ListValue; import com.datadog.debugger.el.values.MapValue; +import com.datadog.debugger.el.values.SetValue; import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; import datadog.trace.bootstrap.debugger.el.ValueReferences; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,18 +42,10 @@ public FilterCollectionExpression(ValueExpression source, BooleanExpression f @Override public CollectionValue evaluate(ValueReferenceResolver valueRefResolver) { - Value collectionValue = source.evaluate(valueRefResolver); - if (collectionValue.isUndefined()) { - return (collectionValue instanceof CollectionValue) - ? (CollectionValue) collectionValue - : CollectionValue.UNDEFINED; - } else if (collectionValue.isNull()) { - return (collectionValue instanceof CollectionValue) - ? (CollectionValue) collectionValue - : CollectionValue.NULL; - } + Value collectionValue = evaluateTargetCollection(source, filterExpression, valueRefResolver); if (collectionValue instanceof ListValue) { ListValue materialized = (ListValue) collectionValue; + checkSupportedList(materialized, this); Collection filtered = new ArrayList<>(); int len = materialized.count(); for (int i = 0; i < len; i++) { @@ -57,6 +59,7 @@ public CollectionValue evaluate(ValueReferenceResolver valueRefResolver) { return new ListValue(filtered); } else if (collectionValue instanceof MapValue) { MapValue materialized = (MapValue) collectionValue; + checkSupportedMap(materialized, this); Map filtered = new HashMap<>(); for (Value key : materialized.getKeys()) { Value value = key.isUndefined() ? Value.undefinedValue() : materialized.get(key); @@ -70,9 +73,22 @@ public CollectionValue evaluate(ValueReferenceResolver valueRefResolver) { } } return new MapValue(filtered); + } else if (collectionValue instanceof SetValue) { + SetValue materialized = (SetValue) collectionValue; + Collection filtered = new HashSet<>(); + Set setHolder = checkSupportedSet(materialized, this); + for (Object value : setHolder) { + if (filterExpression.evaluate( + valueRefResolver.withExtensions( + Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, value)))) { + filtered.add(value); + } + } + return new SetValue(filtered); } - log.warn("Unsupported collection type {}", collectionValue.getValue().getClass().getTypeName()); - return CollectionValue.UNDEFINED; + throw new EvaluationException( + "Unsupported collection type: " + collectionValue.getValue().getClass().getTypeName(), + print(this)); } @Override diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAllExpression.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAllExpression.java index 4b410618618..e22a63ff2ab 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAllExpression.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAllExpression.java @@ -1,7 +1,12 @@ package com.datadog.debugger.el.expressions; +import static com.datadog.debugger.el.PrettyPrintVisitor.print; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedList; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedMap; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedSet; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.evaluateTargetCollection; + import com.datadog.debugger.el.EvaluationException; -import com.datadog.debugger.el.PrettyPrintVisitor; import com.datadog.debugger.el.Value; import com.datadog.debugger.el.Visitor; import com.datadog.debugger.el.values.ListValue; @@ -9,7 +14,6 @@ import com.datadog.debugger.el.values.SetValue; import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; import datadog.trace.bootstrap.debugger.el.ValueReferences; -import datadog.trace.bootstrap.debugger.util.WellKnownClasses; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -29,21 +33,10 @@ public HasAllExpression(ValueExpression valueExpression, BooleanExpression fi @Override public Boolean evaluate(ValueReferenceResolver valueRefResolver) { - if (valueExpression == null) { - throw new EvaluationException( - "Cannot evaluate the expression for null value", PrettyPrintVisitor.print(this)); - } - Value value = valueExpression.evaluate(valueRefResolver); - if (value.isUndefined()) { - throw new EvaluationException( - "Cannot evaluate the expression for undefined value", PrettyPrintVisitor.print(this)); - } - if (value.isNull()) { - throw new EvaluationException( - "Cannot evaluate the expression for null value", PrettyPrintVisitor.print(this)); - } + Value value = evaluateTargetCollection(valueExpression, this, valueRefResolver); if (value instanceof ListValue) { ListValue collection = (ListValue) value; + checkSupportedList(collection, this); if (collection.isEmpty()) { // always return TRUE for empty values (cf vacuous truth, see also Stream::allMatch) return Boolean.TRUE; @@ -61,6 +54,7 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) { } if (value instanceof MapValue) { MapValue map = (MapValue) value; + checkSupportedMap(map, this); if (map.isEmpty()) { // always return TRUE for empty values (cf vacuous truth, see also Stream::allMatch) return Boolean.TRUE; @@ -81,28 +75,22 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) { } if (value instanceof SetValue) { SetValue set = (SetValue) value; + Set setHolder = checkSupportedSet(set, this); if (set.isEmpty()) { // always return TRUE for empty values (cf vacuous truth, see also Stream::allMatch) return Boolean.TRUE; } - Set setHolder = (Set) set.getSetHolder(); - if (WellKnownClasses.isSafe(setHolder)) { - for (Object val : setHolder) { - if (!filterPredicateExpression.evaluate( - valueRefResolver.withExtensions( - Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, val)))) { - return Boolean.FALSE; - } + for (Object val : setHolder) { + if (!filterPredicateExpression.evaluate( + valueRefResolver.withExtensions( + Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, val)))) { + return Boolean.FALSE; } - return Boolean.TRUE; } - throw new EvaluationException( - "Unsupported Set class: " + setHolder.getClass().getTypeName(), - PrettyPrintVisitor.print(this)); + return Boolean.TRUE; } - return filterPredicateExpression.evaluate( - valueRefResolver.withExtensions( - Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, value))); + throw new EvaluationException( + "Unsupported collection class: " + value.getValue().getClass().getTypeName(), print(this)); } @Override diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAnyExpression.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAnyExpression.java index e27db98ffbc..921c7d4cab2 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAnyExpression.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAnyExpression.java @@ -1,7 +1,12 @@ package com.datadog.debugger.el.expressions; +import static com.datadog.debugger.el.PrettyPrintVisitor.print; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedList; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedMap; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.checkSupportedSet; +import static com.datadog.debugger.el.expressions.CollectionExpressionHelper.evaluateTargetCollection; + import com.datadog.debugger.el.EvaluationException; -import com.datadog.debugger.el.PrettyPrintVisitor; import com.datadog.debugger.el.Value; import com.datadog.debugger.el.Visitor; import com.datadog.debugger.el.values.ListValue; @@ -9,7 +14,6 @@ import com.datadog.debugger.el.values.SetValue; import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; import datadog.trace.bootstrap.debugger.el.ValueReferences; -import datadog.trace.bootstrap.debugger.util.WellKnownClasses; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -30,21 +34,10 @@ public HasAnyExpression( @Override public Boolean evaluate(ValueReferenceResolver valueRefResolver) { - if (valueExpression == null) { - throw new EvaluationException( - "Cannot evaluate the expression for null value", PrettyPrintVisitor.print(this)); - } - Value value = valueExpression.evaluate(valueRefResolver); - if (value.isUndefined()) { - throw new EvaluationException( - "Cannot evaluate the expression for undefined value", PrettyPrintVisitor.print(this)); - } - if (value.isNull()) { - throw new EvaluationException( - "Cannot evaluate the expression for null value", PrettyPrintVisitor.print(this)); - } + Value value = evaluateTargetCollection(valueExpression, this, valueRefResolver); if (value instanceof ListValue) { ListValue collection = (ListValue) value; + checkSupportedList(collection, this); if (collection.isEmpty()) { // always return FALSE for empty collection return Boolean.FALSE; @@ -62,6 +55,7 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) { } if (value instanceof MapValue) { MapValue map = (MapValue) value; + checkSupportedMap(map, this); if (map.isEmpty()) { return Boolean.FALSE; } @@ -81,28 +75,22 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) { } if (value instanceof SetValue) { SetValue set = (SetValue) value; + Set setHolder = checkSupportedSet(set, this); if (set.isEmpty()) { return Boolean.FALSE; } - Set setHolder = (Set) set.getSetHolder(); - if (WellKnownClasses.isSafe(setHolder)) { - for (Object val : setHolder) { - if (filterPredicateExpression.evaluate( - valueRefResolver.withExtensions( - Collections.singletonMap( - ValueReferences.ITERATOR_EXTENSION_NAME, Value.of(val))))) { - return Boolean.TRUE; - } + for (Object val : setHolder) { + if (filterPredicateExpression.evaluate( + valueRefResolver.withExtensions( + Collections.singletonMap( + ValueReferences.ITERATOR_EXTENSION_NAME, Value.of(val))))) { + return Boolean.TRUE; } - return Boolean.FALSE; } - throw new EvaluationException( - "Unsupported Set class: " + setHolder.getClass().getTypeName(), - PrettyPrintVisitor.print(this)); + return Boolean.FALSE; } - return filterPredicateExpression.evaluate( - valueRefResolver.withExtensions( - Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, value))); + throw new EvaluationException( + "Unsupported collection class: " + value.getValue().getClass().getTypeName(), print(this)); } @Override diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/IndexExpression.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/IndexExpression.java index 9f3f76ac03e..a3cba06ddd6 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/IndexExpression.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/IndexExpression.java @@ -43,9 +43,13 @@ public Value evaluate(ValueReferenceResolver valueRefResolver) { } else { result = ((MapValue) targetValue).get(objKey); } - } - if (targetValue instanceof ListValue) { + } else if (targetValue instanceof ListValue) { result = ((ListValue) targetValue).get(keyValue.getValue()); + } else { + throw new EvaluationException( + "Cannot evaluate the expression for unsupported type: " + + targetValue.getClass().getTypeName(), + PrettyPrintVisitor.print(this)); } } catch (IllegalArgumentException ex) { throw new EvaluationException(ex.getMessage(), PrettyPrintVisitor.print(this), ex); diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/values/SetValue.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/values/SetValue.java index fa3fbdbbbe6..eb0847b3da3 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/values/SetValue.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/values/SetValue.java @@ -100,6 +100,16 @@ public boolean contains(Value val) { return false; } + @Override + public boolean isNull() { + return setHolder == null || (setHolder instanceof Value && ((Value) setHolder).isNull()); + } + + @Override + public boolean isUndefined() { + return setHolder instanceof Value && ((Value) setHolder).isUndefined(); + } + @Override public R accept(Visitor visitor) { return visitor.visit(this); diff --git a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/FilterCollectionExpressionTest.java b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/FilterCollectionExpressionTest.java index 1c3aa4896a8..38b0ea7e692 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/FilterCollectionExpressionTest.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/FilterCollectionExpressionTest.java @@ -4,14 +4,18 @@ import static com.datadog.debugger.el.PrettyPrintVisitor.print; import static org.junit.jupiter.api.Assertions.*; +import com.datadog.debugger.el.EvaluationException; import com.datadog.debugger.el.RefResolverHelper; import com.datadog.debugger.el.values.CollectionValue; import com.datadog.debugger.el.values.ListValue; import com.datadog.debugger.el.values.MapValue; +import com.datadog.debugger.el.values.SetValue; import datadog.trace.bootstrap.debugger.el.ValueReferences; import datadog.trace.bootstrap.debugger.el.Values; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import org.junit.jupiter.api.Test; @@ -49,9 +53,11 @@ void testNullList() { ListValue collection = new ListValue(null); FilterCollectionExpression expression = new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); - CollectionValue filtered = expression.evaluate(RefResolverHelper.createResolver(this)); - assertEquals(collection, filtered); - assertTrue(filtered.isNull()); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for null value", exception.getMessage()); assertEquals("filter(null, {@it < 2})", print(expression)); } @@ -60,9 +66,11 @@ void testNullObjectList() { ListValue collection = new ListValue(Values.NULL_OBJECT); FilterCollectionExpression expression = new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); - CollectionValue filtered = expression.evaluate(RefResolverHelper.createResolver(this)); - assertEquals(collection, filtered); - assertTrue(filtered.isNull()); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for null value", exception.getMessage()); assertEquals("filter(null, {@it < 2})", print(expression)); } @@ -71,9 +79,11 @@ void testUndefinedList() { ListValue collection = new ListValue(Values.UNDEFINED_OBJECT); FilterCollectionExpression expression = new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); - CollectionValue filtered = expression.evaluate(RefResolverHelper.createResolver(this)); - assertEquals(collection, filtered); - assertTrue(filtered.isUndefined()); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for undefined value", exception.getMessage()); assertEquals("filter(null, {@it < 2})", print(expression)); } @@ -125,9 +135,11 @@ void testNullMap() { MapValue collection = new MapValue(null); FilterCollectionExpression expression = new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); - CollectionValue filtered = expression.evaluate(RefResolverHelper.createResolver(this)); - assertEquals(collection, filtered); - assertTrue(filtered.isNull()); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for null value", exception.getMessage()); assertEquals("filter(null, {@it < 2})", print(expression)); } @@ -136,9 +148,11 @@ void testNullObjectMap() { MapValue collection = new MapValue(Values.NULL_OBJECT); FilterCollectionExpression expression = new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); - CollectionValue filtered = expression.evaluate(RefResolverHelper.createResolver(this)); - assertEquals(collection, filtered); - assertTrue(filtered.isNull()); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for null value", exception.getMessage()); assertEquals("filter(null, {@it < 2})", print(expression)); } @@ -147,9 +161,11 @@ void testUndefinedMap() { MapValue collection = new MapValue(Values.UNDEFINED_OBJECT); FilterCollectionExpression expression = new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); - CollectionValue filtered = expression.evaluate(RefResolverHelper.createResolver(this)); - assertEquals(collection, filtered); - assertTrue(filtered.isUndefined()); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for undefined value", exception.getMessage()); assertEquals("filter(null, {@it < 2})", print(expression)); } @@ -175,4 +191,123 @@ void keyValueMap() { assertEquals(1, filtered.count()); assertEquals("filter(Map, {@value == 2})", print(expression)); } + + @Test + void testMatchingSet() { + SetValue collection = new SetValue(new HashSet<>(Arrays.asList(1, 2, 3))); + FilterCollectionExpression expression = + new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); + CollectionValue filtered = expression.evaluate(RefResolverHelper.createResolver(this)); + assertNotEquals(collection, filtered); + assertEquals(1, filtered.count()); + assertFalse(filtered.isEmpty()); + assertFalse(filtered.isNull()); + assertFalse(filtered.isUndefined()); + assertEquals("filter(Set, {@it < 2})", print(expression)); + } + + @Test + void testEmptySet() { + SetValue collection = new SetValue(new HashSet<>()); + FilterCollectionExpression expression = + new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); + CollectionValue filtered = expression.evaluate(RefResolverHelper.createResolver(this)); + assertNotEquals(collection, filtered); + assertTrue(filtered.isEmpty()); + assertFalse(filtered.isNull()); + assertFalse(filtered.isUndefined()); + assertEquals("filter(Set, {@it < 2})", print(expression)); + } + + @Test + void testNullSet() { + SetValue collection = new SetValue(null); + FilterCollectionExpression expression = + new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for null value", exception.getMessage()); + assertEquals("filter(null, {@it < 2})", print(expression)); + } + + @Test + void testNullObjectSet() { + ListValue collection = new ListValue(Values.NULL_OBJECT); + FilterCollectionExpression expression = + new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for null value", exception.getMessage()); + assertEquals("filter(null, {@it < 2})", print(expression)); + } + + @Test + void testUndefinedSet() { + ListValue collection = new ListValue(Values.UNDEFINED_OBJECT); + FilterCollectionExpression expression = + new FilterCollectionExpression(collection, lt(ref(ValueReferences.ITERATOR_REF), value(2))); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals("Cannot evaluate the expression for undefined value", exception.getMessage()); + assertEquals("filter(null, {@it < 2})", print(expression)); + } + + @Test + void testUnsupportedList() { + ListValue collection = new ListValue(new CustomList()); + FilterCollectionExpression expression = + new FilterCollectionExpression( + collection, eq(ref(ValueReferences.ITERATOR_REF), value("foo"))); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals( + "Unsupported List class: com.datadog.debugger.el.expressions.FilterCollectionExpressionTest$CustomList", + exception.getMessage()); + assertEquals("filter(List, {@it == \"foo\"})", print(expression)); + } + + @Test + void testUnsupportedMap() { + MapValue collection = new MapValue(new CustomMap()); + FilterCollectionExpression expression = + new FilterCollectionExpression(collection, eq(ref(ValueReferences.VALUE_REF), value(2))); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals( + "Unsupported Map class: com.datadog.debugger.el.expressions.FilterCollectionExpressionTest$CustomMap", + exception.getMessage()); + assertEquals("filter(Map, {@value == 2})", print(expression)); + } + + @Test + void testUnsupportedSet() { + SetValue collection = new SetValue(new CustomSet()); + FilterCollectionExpression expression = + new FilterCollectionExpression( + collection, eq(ref(ValueReferences.ITERATOR_REF), value("foo"))); + EvaluationException exception = + assertThrows( + EvaluationException.class, + () -> expression.evaluate(RefResolverHelper.createResolver(this))); + assertEquals( + "Unsupported Set class: com.datadog.debugger.el.expressions.FilterCollectionExpressionTest$CustomSet", + exception.getMessage()); + assertEquals("filter(Set, {@it == \"foo\"})", print(expression)); + } + + static class CustomList extends java.util.ArrayList {} + + static class CustomMap extends HashMap {} + + static class CustomSet extends java.util.HashSet {} } diff --git a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/HasAllExpressionTest.java b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/HasAllExpressionTest.java index c22df80c34c..3b4f69ef0b8 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/HasAllExpressionTest.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/HasAllExpressionTest.java @@ -9,6 +9,9 @@ import com.datadog.debugger.el.EvaluationException; import com.datadog.debugger.el.RefResolverHelper; +import com.datadog.debugger.el.values.ListValue; +import com.datadog.debugger.el.values.MapValue; +import com.datadog.debugger.el.values.SetValue; import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; import datadog.trace.bootstrap.debugger.el.ValueReferences; import datadog.trace.bootstrap.debugger.el.Values; @@ -37,10 +40,9 @@ void testNullPredicate() { assertThrows(EvaluationException.class, () -> undefinedExpression.evaluate(resolver)); assertEquals("Cannot evaluate the expression for undefined value", exception.getMessage()); assertEquals("all(UNDEFINED, {true})", print(undefinedExpression)); - HasAllExpression expression = new HasAllExpression(value(this), null); + HasAllExpression expression = new HasAllExpression(value(new Object[] {this}), null); assertTrue(expression.evaluate(resolver)); - assertEquals( - "all(com.datadog.debugger.el.expressions.HasAllExpressionTest, {true})", print(expression)); + assertEquals("all(java.lang.Object[], {true})", print(expression)); expression = new HasAllExpression(value(Collections.singletonList(this)), null); assertTrue(expression.evaluate(resolver)); assertEquals("all(List, {true})", print(expression)); @@ -90,28 +92,6 @@ void testUndefinedHasAll() { assertEquals("all(UNDEFINED, {testField == 10})", print(expression)); } - @Test - void testSingleElementHasAll() { - ValueReferenceResolver ctx = RefResolverHelper.createResolver(this); - ValueExpression targetExpression = value(this); - HasAllExpression expression = all(targetExpression, TRUE); - assertTrue(expression.evaluate(ctx)); - assertEquals( - "all(com.datadog.debugger.el.expressions.HasAllExpressionTest, {true})", print(expression)); - - expression = all(targetExpression, FALSE); - assertFalse(expression.evaluate(ctx)); - assertEquals( - "all(com.datadog.debugger.el.expressions.HasAllExpressionTest, {false})", - print(expression)); - - expression = all(targetExpression, eq(ref("testField"), value(10))); - assertTrue(expression.evaluate(ctx)); - assertEquals( - "all(com.datadog.debugger.el.expressions.HasAllExpressionTest, {testField == 10})", - print(expression)); - } - @Test void testArrayHasAll() { ValueReferenceResolver ctx = RefResolverHelper.createResolver(this); @@ -264,4 +244,51 @@ void keyValueMap() { assertTrue(expression.evaluate(ctx)); assertEquals("all(Map, {@value == \"a\"})", print(expression)); } + + @Test + void testUnsupportedList() { + ValueReferenceResolver ctx = RefResolverHelper.createResolver(null, null); + ListValue collection = new ListValue(new CustomList()); + HasAllExpression expression = + all(collection, eq(ref(ValueReferences.ITERATOR_REF), value("foo"))); + EvaluationException exception = + assertThrows(EvaluationException.class, () -> expression.evaluate(ctx)); + assertEquals( + "Unsupported List class: com.datadog.debugger.el.expressions.HasAllExpressionTest$CustomList", + exception.getMessage()); + assertEquals("all(List, {@it == \"foo\"})", print(expression)); + } + + @Test + void testUnsupportedMap() { + ValueReferenceResolver ctx = RefResolverHelper.createResolver(null, null); + MapValue collection = new MapValue(new CustomMap()); + HasAllExpression expression = all(collection, eq(ref(ValueReferences.VALUE_REF), value("foo"))); + EvaluationException exception = + assertThrows(EvaluationException.class, () -> expression.evaluate(ctx)); + assertEquals( + "Unsupported Map class: com.datadog.debugger.el.expressions.HasAllExpressionTest$CustomMap", + exception.getMessage()); + assertEquals("all(Map, {@value == \"foo\"})", print(expression)); + } + + @Test + void testUnsupportedSet() { + ValueReferenceResolver ctx = RefResolverHelper.createResolver(null, null); + SetValue collection = new SetValue(new CustomSet()); + HasAllExpression expression = + all(collection, eq(ref(ValueReferences.ITERATOR_REF), value("foo"))); + EvaluationException exception = + assertThrows(EvaluationException.class, () -> expression.evaluate(ctx)); + assertEquals( + "Unsupported Set class: com.datadog.debugger.el.expressions.HasAllExpressionTest$CustomSet", + exception.getMessage()); + assertEquals("all(Set, {@it == \"foo\"})", print(expression)); + } + + static class CustomList extends java.util.ArrayList {} + + static class CustomMap extends HashMap {} + + static class CustomSet extends java.util.HashSet {} } diff --git a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/HasAnyExpressionTest.java b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/HasAnyExpressionTest.java index fb597f06cfb..8a5ca4fa9cf 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/HasAnyExpressionTest.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/HasAnyExpressionTest.java @@ -7,7 +7,9 @@ import com.datadog.debugger.el.DSL; import com.datadog.debugger.el.EvaluationException; import com.datadog.debugger.el.RefResolverHelper; -import com.datadog.debugger.el.values.ObjectValue; +import com.datadog.debugger.el.values.ListValue; +import com.datadog.debugger.el.values.MapValue; +import com.datadog.debugger.el.values.SetValue; import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; import datadog.trace.bootstrap.debugger.el.ValueReferences; import datadog.trace.bootstrap.debugger.el.Values; @@ -36,10 +38,9 @@ void testNullPredicate() { assertThrows(EvaluationException.class, () -> undefinedExpression.evaluate(resolver)); assertEquals("Cannot evaluate the expression for undefined value", exception.getMessage()); assertEquals("any(UNDEFINED, {true})", print(undefinedExpression)); - HasAnyExpression expression = new HasAnyExpression(value(this), null); + HasAnyExpression expression = new HasAnyExpression(value(new Object[] {this}), null); assertTrue(expression.evaluate(resolver)); - assertEquals( - "any(com.datadog.debugger.el.expressions.HasAnyExpressionTest, {true})", print(expression)); + assertEquals("any(java.lang.Object[], {true})", print(expression)); expression = new HasAnyExpression(value(Collections.singletonList(this)), null); assertTrue(expression.evaluate(resolver)); assertEquals("any(List, {true})", print(expression)); @@ -89,31 +90,6 @@ void testUndefinedHasAny() { assertEquals("any(UNDEFINED, {testField == 10})", print(undefinedExpression2)); } - @Test - void testSingleElementHasAny() { - ValueReferenceResolver ctx = RefResolverHelper.createResolver(null, null); - ValueExpression targetExpression = new ObjectValue(this); - HasAnyExpression expression = any(targetExpression, TRUE); - assertTrue(expression.evaluate(ctx)); - assertEquals( - "any(com.datadog.debugger.el.expressions.HasAnyExpressionTest, {true})", print(expression)); - - expression = any(targetExpression, FALSE); - assertFalse(expression.evaluate(ctx)); - assertEquals( - "any(com.datadog.debugger.el.expressions.HasAnyExpressionTest, {false})", - print(expression)); - - expression = - any( - targetExpression, - eq(getMember(ref(ValueReferences.ITERATOR_REF), "testField"), value(10))); - assertTrue(expression.evaluate(ctx)); - assertEquals( - "any(com.datadog.debugger.el.expressions.HasAnyExpressionTest, {@it.testField == 10})", - print(expression)); - } - @Test void testArrayHasAny() { ValueReferenceResolver ctx = RefResolverHelper.createResolver(null, null); @@ -265,4 +241,51 @@ void keyValueMap() { assertTrue(expression.evaluate(ctx)); assertEquals("any(Map, {@value == \"a\"})", print(expression)); } + + @Test + void testUnsupportedList() { + ValueReferenceResolver ctx = RefResolverHelper.createResolver(null, null); + ListValue collection = new ListValue(new CustomList()); + HasAnyExpression expression = + any(collection, eq(ref(ValueReferences.ITERATOR_REF), value("foo"))); + EvaluationException exception = + assertThrows(EvaluationException.class, () -> expression.evaluate(ctx)); + assertEquals( + "Unsupported List class: com.datadog.debugger.el.expressions.HasAnyExpressionTest$CustomList", + exception.getMessage()); + assertEquals("any(List, {@it == \"foo\"})", print(expression)); + } + + @Test + void testUnsupportedMap() { + ValueReferenceResolver ctx = RefResolverHelper.createResolver(null, null); + MapValue collection = new MapValue(new CustomMap()); + HasAnyExpression expression = any(collection, eq(ref(ValueReferences.VALUE_REF), value("foo"))); + EvaluationException exception = + assertThrows(EvaluationException.class, () -> expression.evaluate(ctx)); + assertEquals( + "Unsupported Map class: com.datadog.debugger.el.expressions.HasAnyExpressionTest$CustomMap", + exception.getMessage()); + assertEquals("any(Map, {@value == \"foo\"})", print(expression)); + } + + @Test + void testUnsupportedSet() { + ValueReferenceResolver ctx = RefResolverHelper.createResolver(null, null); + SetValue collection = new SetValue(new CustomSet()); + HasAnyExpression expression = + any(collection, eq(ref(ValueReferences.ITERATOR_REF), value("foo"))); + EvaluationException exception = + assertThrows(EvaluationException.class, () -> expression.evaluate(ctx)); + assertEquals( + "Unsupported Set class: com.datadog.debugger.el.expressions.HasAnyExpressionTest$CustomSet", + exception.getMessage()); + assertEquals("any(Set, {@it == \"foo\"})", print(expression)); + } + + static class CustomList extends java.util.ArrayList {} + + static class CustomMap extends HashMap {} + + static class CustomSet extends java.util.HashSet {} } diff --git a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/IndexExpressionTest.java b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/IndexExpressionTest.java index 4ed789f1046..910a257fe8e 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/IndexExpressionTest.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/IndexExpressionTest.java @@ -9,12 +9,14 @@ import com.datadog.debugger.el.RefResolverHelper; import com.datadog.debugger.el.Value; import com.datadog.debugger.el.values.NumericValue; +import com.datadog.debugger.el.values.SetValue; import com.datadog.debugger.el.values.StringValue; import datadog.trace.api.Config; import datadog.trace.bootstrap.debugger.util.Redaction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.UUID; @@ -74,6 +76,18 @@ void testMap() { assertEquals("strMap[\"foo\"]", print(expr)); } + @Test + void testUnsupported() { + IndexExpression expr = + new IndexExpression(new SetValue(new HashSet<>()), new StringValue("foo")); + EvaluationException evaluationException = + assertThrows( + EvaluationException.class, () -> expr.evaluate(RefResolverHelper.createResolver(this))); + assertEquals( + "Cannot evaluate the expression for unsupported type: com.datadog.debugger.el.values.SetValue", + evaluationException.getMessage()); + } + @Test void undefined() { IndexExpression expr = new IndexExpression(ValueExpression.UNDEFINED, new NumericValue(1)); diff --git a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/ListValueTest.java b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/ListValueTest.java index eec9fed3316..ca2a3d3d95a 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/ListValueTest.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/ListValueTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.*; import com.datadog.debugger.el.Value; +import datadog.trace.bootstrap.debugger.el.Values; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; @@ -84,4 +85,14 @@ void testFromArrayOfArrays() { assertThrows(IllegalArgumentException.class, () -> listValue.get(intArray.length)); assertEquals("int[][]", print(listValue)); } + + @Test + void nullList() { + ListValue listValue = new ListValue(null); + assertTrue(listValue.isEmpty()); + assertTrue(listValue.isNull()); + listValue = new ListValue(Values.NULL_OBJECT); + assertTrue(listValue.isEmpty()); + assertTrue(listValue.isNull()); + } } diff --git a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/MapValueTest.java b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/MapValueTest.java index 14c45ef5245..1c711aceee5 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/MapValueTest.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/MapValueTest.java @@ -60,4 +60,14 @@ void intMap() { Value key = Value.of(1); assertEquals(Value.of(1), instance.get(key)); } + + @Test + void nullMap() { + MapValue mapValue = new MapValue(null); + assertTrue(mapValue.isEmpty()); + assertTrue(mapValue.isNull()); + mapValue = new MapValue(Values.NULL_OBJECT); + assertTrue(mapValue.isEmpty()); + assertTrue(mapValue.isNull()); + } } diff --git a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/SetValueTest.java b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/SetValueTest.java index d77a120ce52..b7e01059bfb 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/SetValueTest.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/values/SetValueTest.java @@ -47,4 +47,14 @@ void get() { assertEquals(Value.undefinedValue(), instance.get(Values.UNDEFINED_OBJECT)); assertEquals(Value.undefinedValue(), instance.get(Value.undefinedValue())); } + + @Test + void nullSet() { + SetValue setValue = new SetValue(null); + assertTrue(setValue.isEmpty()); + assertTrue(setValue.isNull()); + setValue = new SetValue(Values.NULL_OBJECT); + assertTrue(setValue.isEmpty()); + assertTrue(setValue.isNull()); + } }