From f49ea029263935d3d0595e55e7cffbef4567af13 Mon Sep 17 00:00:00 2001 From: Jim Larson Date: Sat, 20 Jun 2020 19:41:25 -0700 Subject: [PATCH 1/2] Document equality. --- doc/langdef.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/doc/langdef.md b/doc/langdef.md index 261b633a..c55734e3 100644 --- a/doc/langdef.md +++ b/doc/langdef.md @@ -783,6 +783,49 @@ All predefined operators, functions and constants are listed in the table below. For each symbol, the available overloads are listed. Operator symbols use a notation like `_+_` where `_` is a placeholder for an argument. +### Equality and Ordering + +Equality (`_==_`) and inequality (`_!=_`) are defined for all types. Inequality +is the logical negation of equality, i.e. `e1 != e2` is the same as `!(e1 == +e2)` for all expressions `e1` and `e2`. + +Equality and inequality are homogeneous; comparing values of different runtime +types results in a runtime error. Thus `2 == 3` is false, but `2 == 2.0` is an +error. + +For `double`, all not-a-number (`NaN`) values compare equal. This is different +than the usual semantics of floating-point numbers, but it is more consistent +with the usual expectations of reflexivity, and is more compatible with the +usual notions of equality on protocol buffers. + +Lists are unequal if their lengths are different. Otherwise, for lists `a` and +`b` with length `N`, `a == b` is equivalent to + +``` +a[0] == b[0] && a[1] == b[2] && ... && a[N-1] == b[N-1] +``` + +Maps are unequal if their key sets are different, otherwise for maps `a` and +`b` with keyset `k1, k2, ..., kN`, `a == b` is equivalent to + +``` +a[k1] == b[k1] && a[k2] == b[k2] && ... && a[kN] == b[kN] +``` + +So for equality of both lists and maps this means: + +- if the list lengths / map key sets are different, the result is false; +- if one or more element comparisons is false, the result is false; +- if all element comparisons are true, the result is true; +- otherwise the result is an error. + +Ordering operators are defined for `int`, `uint`, `double`, `string`, `bytes`, +`bool`, as well as `timestamp` and `duration`. Strings obey lexicographic +ordering of the code points, and bytes obey lexicographic ordering of the byte +values. The ordering operators obey the usual algebraic properties, i.e. `e1 <= +e2` gives the same result as `!(e1 > e2)` as well as `(e1 < e2) || (e1 == e2)` +when the expressions involved do not have side effects. + ### Timezones Timezones are expressed in the following grammar: From 9bcc752e2d4ecf84d26f673e615cc7095ac7d617 Mon Sep 17 00:00:00 2001 From: Jim Larson Date: Sun, 21 Jun 2020 14:01:05 -0700 Subject: [PATCH 2/2] Conformance tests and doc tweaks. --- doc/langdef.md | 2 +- tests/simple/testdata/comparisons.textproto | 24 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/doc/langdef.md b/doc/langdef.md index c55734e3..18b88cf3 100644 --- a/doc/langdef.md +++ b/doc/langdef.md @@ -802,7 +802,7 @@ Lists are unequal if their lengths are different. Otherwise, for lists `a` and `b` with length `N`, `a == b` is equivalent to ``` -a[0] == b[0] && a[1] == b[2] && ... && a[N-1] == b[N-1] +a[0] == b[0] && a[1] == b[1] && ... && a[N-1] == b[N-1] ``` Maps are unequal if their key sets are different, otherwise for maps `a` and diff --git a/tests/simple/testdata/comparisons.textproto b/tests/simple/testdata/comparisons.textproto index f7dabfc3..993bff24 100644 --- a/tests/simple/testdata/comparisons.textproto +++ b/tests/simple/testdata/comparisons.textproto @@ -2,7 +2,7 @@ name: "comparisons" description: "Tests for boolean-valued functions and operators." section { name: "eq_literal" - description: "Literals comparison on _=_" + description: "Literals comparison on _==_" test { name: "eq_int" expr: "1 == 1" @@ -33,6 +33,12 @@ section { expr: "-1.0 == 1.0" value: { bool_value: false } } + test { + name: "eq_double_NaN" + description: "CEL defines all NaN values to be equal." + expr: "1.0 / 0.0 == 1.0 / 0.0" + value: { bool_value: true } + } test { name: "eq_string" expr: "'' == \"\"" @@ -121,6 +127,17 @@ section { expr: "['case'] == ['cAse']" value: { bool_value: false } } + test { + name: "not_eq_list_length" + expr: "['one'] == [2, 3]" + disable_check: true + value: { bool_value: false } + } + test { + name: "not_eq_list_false_vs_types" + expr: "[1, 'dos', 3] == [1, 2, 4]" + value: { bool_value: false } + } test { name: "eq_map_empty" expr: "{} == {}" @@ -156,6 +173,11 @@ section { expr: "{'key':'value'} == {'Key':'value'}" value: { bool_value: false } } + test { + name: "not_eq_map_false_vs_types" + expr: "{'k1': 1, 'k2': 'dos', 'k3': 3} == {'k1': 1, 'k2': 2, 'k3': 4}" + value: { bool_value: false } + } test { name: "eq_mixed_types_error" description: "A mix of types fails during type checks but can't be captured in the conformance tests yet (See google/cel-go#155). Also, if you disable checks it yields {bool_value: false} where it should also yield an error"