More OPA conformance (#77)

- object.union
- object.union_n
- treat negative integers as two separate tokens (Sub and Number)
  when seen in arithmetic expressions
- Ensure that fully query string is parsed
- Evaluate queries in a separate module instead of the last read module.
  This correctly handles queries of the form `x = data.test.y` where x is
  already a ref in `data.test`
- Handle queries producing multiple outputs in test infrastructure
- Add tests for engine
- Add tests locking down valid queries
- Update opa.passing

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2023-12-27 17:00:40 -08:00
committed by GitHub
parent e61b406547
commit e549882b07
9 changed files with 204 additions and 25 deletions
@@ -0,0 +1,21 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
cases:
- note: negative-integer-literal-in-arithmetic-expressions
data: {}
modules:
- |
# In the following, the negative integer must be broken into a - and an integer tokens
# when in arighmetic expression contexts
package test
a = 1+1-1
b = 1 +1 -1
c = 1 + 1 - 1
d = -1 -1
query: data.test
want_result:
a: 1
b: 1
c: 1
d: -2
+44
View File
@@ -0,0 +1,44 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
cases:
- note: trailing whitespace in query
data: {}
modules: ["package test"]
query: "1 + 1 -2 "
want_result: 0
- note: trailing chars in query
data: {}
modules: ["package test"]
query: "[1]]"
error: expecting EOF
- note: trailing expressions in query
data: {}
modules: ["package test"]
query: "1 2"
error: expecting EOF
- note: multiple statements in query
data: {}
modules: ["package test"]
query: |
a = [1, 2, 3]
true
y = 1 + 1
want_result:
a: [1, 2, 3]
y: 2
- note: comprehensions in query
data: {}
modules: ["package test"]
query: |
true
[1, 2, 3][_]
want_result:
many!:
- [true, 1]
- [true, 2]
- [true, 3]
+20 -5
View File
@@ -83,6 +83,7 @@ fn match_values(computed: &Value, expected: &Value) -> Result<()> {
pub fn check_output(computed_results: &[Value], expected_results: &[Value]) -> Result<()> {
if computed_results.len() != expected_results.len() {
dbg!((&computed_results, &expected_results));
bail!(
"the number of computed results ({}) and expected results ({}) is not equal",
computed_results.len(),
@@ -108,11 +109,25 @@ pub fn check_output(computed_results: &[Value], expected_results: &[Value]) -> R
}
fn push_query_results(query_results: QueryResults, results: &mut Vec<Value>) {
if let Some(query_result) = query_results.result.last() {
if !query_result.bindings.is_empty_object() {
results.push(query_result.bindings.clone());
} else if let Some(v) = query_result.expressions.last() {
results.push(v.value.clone());
if query_results.result.len() == 1 {
if let Some(query_result) = query_results.result.last() {
if !query_result.bindings.is_empty_object() {
results.push(query_result.bindings.clone());
} else {
for e in query_result.expressions.iter() {
results.push(e.value.clone());
}
}
}
} else {
for r in query_results.result.iter() {
if !r.bindings.is_empty_object() {
results.push(r.bindings.clone());
} else {
results.push(Value::from_array(
r.expressions.iter().map(|e| e.value.clone()).collect(),
));
}
}
}
}
+5
View File
@@ -48,6 +48,7 @@ indirectreferences
inputvalues
intersection
invalidkeyerror
jsonbuiltins
jsonfilter
jsonfilteridempotent
jsonremove
@@ -67,7 +68,11 @@ objectkeys
objectremove
objectremoveidempotent
objectremovenonstringkey
objectunion
objectunionn
partialdocconstants
partialiter
partialobjectdoc
partialsetdoc
planner-ir
rand
+5 -1
View File
@@ -170,7 +170,11 @@ fn run_opa_tests(opa_tests_dir: String, folders: &[String]) -> Result<()> {
entry.0 += 1;
}
// TODO: Handle tests that specify both want_result and strict_error
(Err(_), _) if case.want_error.is_some() => {
(Err(_), _)
if case.want_error.is_some()
|| case.strict_error == Some(true)
|| case.want_error_code.is_some() =>
{
// Expected failure.
entry.0 += 1;
}