Skip to content

Commit 879305f

Browse files
jnthntatumcopybara-github
authored andcommitted
Enable conformance tests for two-var comprehensions.
Add existsOne (preferred alternative to older exists_one) PiperOrigin-RevId: 853942944
1 parent f7b9112 commit 879305f

10 files changed

Lines changed: 112 additions & 3 deletions

File tree

bundle/src/test/java/dev/cel/bundle/CelEnvironmentExporterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public void standardLibrarySubset_favorExclusion() throws Exception {
110110
FunctionSelector.create("matches", ImmutableSet.of()),
111111
FunctionSelector.create(
112112
"timestamp", ImmutableSet.of("string_to_timestamp"))))
113-
.setExcludedMacros(ImmutableSet.of("map", "filter"))
113+
.setExcludedMacros(ImmutableSet.of("map", "existsOne", "filter"))
114114
.build());
115115
}
116116

common/src/main/java/dev/cel/common/Operator.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public enum Operator {
4646
ALL("all"),
4747
EXISTS("exists"),
4848
EXISTS_ONE("exists_one"),
49+
EXISTS_ONE_NEW("existsOne"),
4950
MAP("map"),
5051
FILTER("filter"),
5152
NOT_STRICTLY_FALSE("@not_strictly_false"),
@@ -109,6 +110,7 @@ public static Optional<Operator> find(String text) {
109110
.put(EQUALS.getFunction(), EQUALS)
110111
.put(EXISTS.getFunction(), EXISTS)
111112
.put(EXISTS_ONE.getFunction(), EXISTS_ONE)
113+
.put(EXISTS_ONE_NEW.getFunction(), EXISTS_ONE_NEW)
112114
.put(FILTER.getFunction(), FILTER)
113115
.put(GREATER.getFunction(), GREATER)
114116
.put(GREATER_EQUALS.getFunction(), GREATER_EQUALS)

conformance/src/test/java/dev/cel/conformance/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ _ALL_TESTS = [
7575
"@cel_spec//tests/simple:testdata/lists.textproto",
7676
"@cel_spec//tests/simple:testdata/logic.textproto",
7777
"@cel_spec//tests/simple:testdata/macros.textproto",
78+
"@cel_spec//tests/simple:testdata/macros2.textproto",
7879
"@cel_spec//tests/simple:testdata/math_ext.textproto",
7980
"@cel_spec//tests/simple:testdata/namespace.textproto",
8081
"@cel_spec//tests/simple:testdata/optionals.textproto",

conformance/src/test/java/dev/cel/conformance/ConformanceTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public final class ConformanceTest extends Statement {
6666
.setOptions(OPTIONS)
6767
.addLibraries(
6868
CelExtensions.bindings(),
69+
CelExtensions.comprehensions(),
6970
CelExtensions.encoders(OPTIONS),
7071
CelExtensions.math(OPTIONS),
7172
CelExtensions.protos(),
@@ -80,6 +81,7 @@ public final class ConformanceTest extends Statement {
8081
.setOptions(OPTIONS)
8182
.addLibraries(
8283
CelExtensions.bindings(),
84+
CelExtensions.comprehensions(),
8385
CelExtensions.encoders(OPTIONS),
8486
CelExtensions.math(OPTIONS),
8587
CelExtensions.protos(),
@@ -106,10 +108,12 @@ private static CelChecker getChecker(SimpleTest test) throws Exception {
106108
.addFileTypes(dev.cel.expr.conformance.proto2.TestAllTypesExtensions.getDescriptor())
107109
.addLibraries(
108110
CelExtensions.bindings(),
111+
CelExtensions.comprehensions(),
109112
CelExtensions.encoders(OPTIONS),
110113
CelExtensions.math(OPTIONS),
111114
CelExtensions.sets(OPTIONS),
112115
CelExtensions.strings(),
116+
CelExtensions.comprehensions(),
113117
CelOptionalLibrary.INSTANCE)
114118
.addMessageTypes(dev.cel.expr.conformance.proto2.TestAllTypes.getDescriptor())
115119
.addMessageTypes(dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor())
@@ -120,6 +124,7 @@ private static CelChecker getChecker(SimpleTest test) throws Exception {
120124
CelRuntimeFactory.standardCelRuntimeBuilder()
121125
.setOptions(OPTIONS)
122126
.addLibraries(
127+
CelExtensions.comprehensions(),
123128
CelExtensions.encoders(OPTIONS),
124129
CelExtensions.math(OPTIONS),
125130
CelExtensions.sets(OPTIONS),
@@ -182,6 +187,7 @@ public void evaluate() throws Throwable {
182187
CelValidationResult response = getParser(test).parse(test.getExpr(), test.getName());
183188
assertThat(response.hasError()).isFalse();
184189
response = getChecker(test).check(response.getAst());
190+
System.out.println("response: " + response.getIssueString());
185191
assertThat(response.hasError()).isFalse();
186192
Type resultType = CelProtoTypes.celTypeToType(response.getAst().getResultType());
187193

extensions/src/main/java/dev/cel/extensions/CelComprehensionsExtensions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ public ImmutableSet<CelMacro> macros() {
159159
Operator.EXISTS_ONE.getFunction(),
160160
3,
161161
CelComprehensionsExtensions::expandExistsOneMacro),
162+
CelMacro.newReceiverMacro(
163+
Operator.EXISTS_ONE_NEW.getFunction(),
164+
3,
165+
CelComprehensionsExtensions::expandExistsOneMacro),
162166
CelMacro.newReceiverMacro(
163167
"transformList", 3, CelComprehensionsExtensions::transformListMacro),
164168
CelMacro.newReceiverMacro(

parser/src/main/java/dev/cel/parser/CelStandardMacro.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ public enum CelStandardMacro {
5454
CelMacro.newReceiverMacro(
5555
Operator.EXISTS_ONE.getFunction(), 2, CelStandardMacro::expandExistsOneMacro)),
5656

57+
/**
58+
* Boolean comprehension which asserts that a predicate holds true for exactly one element in the
59+
* input range.
60+
*/
61+
EXISTS_ONE_NEW(
62+
CelMacro.newReceiverMacro(
63+
Operator.EXISTS_ONE_NEW.getFunction(), 2, CelStandardMacro::expandExistsOneMacro)),
64+
5765
/**
5866
* Comprehension which applies a transform to each element in the input range and produces a list
5967
* of equivalent size as output.

parser/src/test/java/dev/cel/parser/CelParserImplTest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static com.google.common.truth.Truth.assertThat;
1818
import static org.junit.Assert.assertThrows;
1919

20+
import com.google.common.collect.ImmutableSet;
2021
import com.google.testing.junit.testparameterinjector.TestParameter;
2122
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
2223
import com.google.testing.junit.testparameterinjector.TestParameters;
@@ -260,10 +261,17 @@ public void parse_exprUnderMaxRecursionLimit_doesNotThrow(
260261
@TestParameters("{expression: 'A.all(a?b, c)'}")
261262
@TestParameters("{expression: 'A.exists(a?b, c)'}")
262263
@TestParameters("{expression: 'A.exists_one(a?b, c)'}")
264+
@TestParameters("{expression: 'A.existsOne(a?b, c)'}")
263265
@TestParameters("{expression: 'A.filter(a?b, c)'}")
264266
public void parse_macroArgumentContainsSyntaxError_throws(String expression) {
265267
CelParser parser =
266-
CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build();
268+
CelParserImpl.newBuilder()
269+
.setStandardMacros(
270+
ImmutableSet.<CelStandardMacro>builder()
271+
.addAll(CelStandardMacro.STANDARD_MACROS)
272+
.add(CelStandardMacro.EXISTS_ONE_NEW)
273+
.build())
274+
.build();
267275

268276
CelValidationResult parseResult = parser.parse(expression);
269277

parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.auto.value.AutoValue;
2727
import com.google.common.base.Ascii;
2828
import com.google.common.base.Joiner;
29+
import com.google.common.collect.ImmutableSet;
2930
import com.google.errorprone.annotations.Immutable;
3031
import com.google.protobuf.Descriptors.Descriptor;
3132
import com.google.protobuf.Descriptors.EnumDescriptor;
@@ -57,7 +58,11 @@
5758
public final class CelParserParameterizedTest extends BaselineTestCase {
5859
private static final CelParser PARSER =
5960
CelParserFactory.standardCelParserBuilder()
60-
.setStandardMacros(CelStandardMacro.STANDARD_MACROS)
61+
.setStandardMacros(
62+
ImmutableSet.<CelStandardMacro>builder()
63+
.addAll(CelStandardMacro.STANDARD_MACROS)
64+
.add(CelStandardMacro.EXISTS_ONE_NEW)
65+
.build())
6166
.addLibraries(CelOptionalLibrary.INSTANCE)
6267
.addMacros(
6368
CelMacro.newGlobalVarArgMacro("noop_macro", (a, b, c) -> Optional.empty()),
@@ -162,6 +167,7 @@ public void parser() {
162167
runTest(PARSER, "aaa.bbb(ccc)");
163168
runTest(PARSER, "has(m.f)");
164169
runTest(PARSER, "m.exists_one(v, f)");
170+
runTest(PARSER, "m.existsOne(v, f)");
165171
runTest(PARSER, "m.map(v, f)");
166172
runTest(PARSER, "m.map(v, p, f)");
167173
runTest(PARSER, "m.filter(v, p)");

parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public void getFunction() {
3232
assertThat(CelStandardMacro.EXISTS.getFunction()).isEqualTo(Operator.EXISTS.getFunction());
3333
assertThat(CelStandardMacro.EXISTS_ONE.getFunction())
3434
.isEqualTo(Operator.EXISTS_ONE.getFunction());
35+
assertThat(CelStandardMacro.EXISTS_ONE_NEW.getFunction())
36+
.isEqualTo(Operator.EXISTS_ONE_NEW.getFunction());
3537
assertThat(CelStandardMacro.FILTER.getFunction()).isEqualTo(Operator.FILTER.getFunction());
3638
assertThat(CelStandardMacro.MAP.getFunction()).isEqualTo(Operator.MAP.getFunction());
3739
assertThat(CelStandardMacro.MAP_FILTER.getFunction()).isEqualTo(Operator.MAP.getFunction());
@@ -90,6 +92,21 @@ public void testExistsOne() {
9092
.isEqualTo(CelStandardMacro.EXISTS_ONE.getDefinition().getKey().hashCode());
9193
}
9294

95+
@Test
96+
public void testExistsOneNew() {
97+
assertThat(CelStandardMacro.EXISTS_ONE_NEW.getFunction())
98+
.isEqualTo(Operator.EXISTS_ONE_NEW.getFunction());
99+
assertThat(CelStandardMacro.EXISTS_ONE_NEW.getDefinition().getArgumentCount()).isEqualTo(2);
100+
assertThat(CelStandardMacro.EXISTS_ONE_NEW.getDefinition().isReceiverStyle()).isTrue();
101+
assertThat(CelStandardMacro.EXISTS_ONE_NEW.getDefinition().getKey())
102+
.isEqualTo("existsOne:2:true");
103+
assertThat(CelStandardMacro.EXISTS_ONE_NEW.getDefinition().isVariadic()).isFalse();
104+
assertThat(CelStandardMacro.EXISTS_ONE_NEW.getDefinition().toString())
105+
.isEqualTo(CelStandardMacro.EXISTS_ONE_NEW.getDefinition().getKey());
106+
assertThat(CelStandardMacro.EXISTS_ONE_NEW.getDefinition().hashCode())
107+
.isEqualTo(CelStandardMacro.EXISTS_ONE_NEW.getDefinition().getKey().hashCode());
108+
}
109+
93110
@Test
94111
public void testMap2() {
95112
assertThat(CelStandardMacro.MAP.getFunction()).isEqualTo(Operator.MAP.getFunction());

parser/src/test/resources/parser.baseline

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,63 @@ M: m^#1:Expr.Ident#.exists_one(
784784
f^#4:Expr.Ident#
785785
)^#0:Expr.Call#
786786

787+
I: m.existsOne(v, f)
788+
=====>
789+
P: __comprehension__(
790+
// Variable
791+
v,
792+
// Target
793+
m^#1:Expr.Ident#,
794+
// Accumulator
795+
@result,
796+
// Init
797+
0^#5:int64#,
798+
// LoopCondition
799+
true^#6:bool#,
800+
// LoopStep
801+
_?_:_(
802+
f^#4:Expr.Ident#,
803+
_+_(
804+
@result^#7:Expr.Ident#,
805+
1^#8:int64#
806+
)^#9:Expr.Call#,
807+
@result^#10:Expr.Ident#
808+
)^#11:Expr.Call#,
809+
// Result
810+
_==_(
811+
@result^#12:Expr.Ident#,
812+
1^#13:int64#
813+
)^#14:Expr.Call#)^#15:Expr.Comprehension#
814+
L: __comprehension__(
815+
// Variable
816+
v,
817+
// Target
818+
m^#1[1,0]#,
819+
// Accumulator
820+
@result,
821+
// Init
822+
0^#5[1,11]#,
823+
// LoopCondition
824+
true^#6[1,11]#,
825+
// LoopStep
826+
_?_:_(
827+
f^#4[1,15]#,
828+
_+_(
829+
@result^#7[1,11]#,
830+
1^#8[1,11]#
831+
)^#9[1,11]#,
832+
@result^#10[1,11]#
833+
)^#11[1,11]#,
834+
// Result
835+
_==_(
836+
@result^#12[1,11]#,
837+
1^#13[1,11]#
838+
)^#14[1,11]#)^#15[1,11]#
839+
M: m^#1:Expr.Ident#.existsOne(
840+
v^#3:Expr.Ident#,
841+
f^#4:Expr.Ident#
842+
)^#0:Expr.Call#
843+
787844
I: m.map(v, f)
788845
=====>
789846
P: __comprehension__(

0 commit comments

Comments
 (0)