feat!: add Rego Virtual Machine (RVM) implementation (#495)

* feat!: add Rego Virtual Machine (RVM) implementation

This commit introduces a register-based virtual machine for executing Rego
policies with bytecode-style instructions. Unlike the existing tree-walking
interpreter, the RVM compiles policies into instruction sequences that operate
on virtual registers, offering better performance and optimization potential.

Core Components:

Instruction Set Architecture:
- Define instruction types for data operations, control flow, and builtins
- Implement instruction parameter encoding and display formatting
- Add instruction parser with comprehensive test coverage

Virtual Machine Engine:
- Register-based execution model with program counter management
- Loop execution supporting iterators, comprehensions, and quantifiers
- Function call handling with argument evaluation and context management
- Rule evaluation with default value resolution and virtual data support
- Arithmetic and comparison operation implementations

Program Representation:
- Program listing builder with instruction sequencing
- Rule tree construction for organizing policy rules
- Binary and JSON serialization for compiled programs
- Recompilation support for program modification

Testing Infrastructure:
- Extensive YAML test suites covering all VM features
- Rust unit tests for VM execution and instruction parsing
- Test suites for loops, comprehensions, builtins, and control flow

BREAKING CHANGE: Introduces new VM execution path alongside interpreter

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>

* docs: add detailed RVM architecture references

Introduce architecture.md explaining program artifacts, serialization, and runtime subsystems.
Document the full opcode catalog in instruction-set.md, including operands, parameter tables, and outcomes.
Walk through execution flow, stacks, and operational guidance in vm-runtime.md, tying the runtime to the new architecture docs.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>

---------

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2025-11-14 11:43:19 -06:00
committed by GitHub
parent 6dc505c88b
commit 49bd3c22f3
89 changed files with 19158 additions and 313 deletions

78
tests/rvm/vm/README.md Normal file
View File

@@ -0,0 +1,78 @@
# Regorus VM Test Suites
This directory hosts YAML-driven regression suites for the Regorus virtual machine. Each YAML file is converted into parameterised Rust tests by `src/rvm/tests/vm.rs`, so the contents here define the end-to-end VM coverage.
## Prerequisites
- Enable the `rvm` feature (it pulls in `std` and the VM runtime) whenever you run these tests:
- `cargo test --features rvm run_vm_test_file`
- `cargo test --features rvm run_loop_test_file`
- Append `-- --nocapture` to surface per-test diagnostics when a failure occurs.
- Individual generated tests follow the pattern `run_vm_test_file_tests_rvm_vm_suites_<suite>_yaml`, so you can use that fragment with `cargo test` to run a single suite.
## Layout
- `suites/*.yaml` — primary instruction, control-flow, and integration suites.
- `suites/loops/*.yaml` — dedicated loop/comprehension suites.
- Mirror the comment headers inside each suite when adding new files; the descriptions are surfaced in this README for quick reference.
## Main Suites (`suites/*.yaml`)
| Suite | Focus |
| --- | --- |
| `arithmetic_operations.yaml` | Arithmetic opcodes (`Add`, `Sub`, `Mul`, `Div`, `Mod`) and simple expressions. |
| `assertions.yaml` | `AssertCondition` semantics, including success/failure and loop control interactions. |
| `basic_instructions.yaml` | Core load/move/return instructions that underpin every program. |
| `boolean_literals.yaml` | `LoadBool`, `LoadTrue`, `LoadFalse`, and their interaction with logical operators. |
| `builtin_functions.yaml` | Builtin dispatch covering argument marshalling, return handling, and error cases. |
| `call_rule.yaml` | `CallRule` execution, rule caches, defaults, and fallbacks. |
| `comparison_operations.yaml` | Relational operators plus logical combining (`Eq`, `Ne`, `Lt`, `Le`, `Gt`, `Ge`, `And`, `Or`, `Not`). |
| `complex.yaml` | Deeply nested hybrid loops, comprehensions, and rule calls that stress the scheduler. |
| `constructed_collections.yaml` | `ArrayCreate`/`SetCreate` success paths, undefined propagation, and deduplication. |
| `control_flow.yaml` | Conditional branching patterns, nested assertions, and selection logic. |
| `core_semantics.yaml` | Broad regression coverage for arithmetic, comparisons, loops, assertions, and collection helpers. |
| `data_structures.yaml` | Array/object/set creation, access, and mutation instructions. |
| `deep_nesting.yaml` | Three-plus levels of mixed loop modes validating register pressure and control flow correctness. |
| `default_rules.yaml` | Complete rule execution with default literals and failure fallbacks. |
| `destructuring_rules.yaml` | Destructuring metadata handling, success/early-exit semantics. |
| `function_calls.yaml` | User function invocation plumbing, argument passing, and returns. |
| `halt.yaml` | `Halt` instruction returning register `0` and stopping execution. |
| `host_await.yaml` | Successful `HostAwait` responses across execution modes and run-to-completion flows. |
| `host_await_failures.yaml` | Error signalling and ignore-flag behaviour for `HostAwait`. |
| `indexed_access.yaml` | Literal/register indexing, chained accesses, and undefined propagation. |
| `integration_scenarios.yaml` | Real-world policy shapes (RBAC, filtering, transforms, workflows). |
| `interpreter_operator_compatibility.yaml` | Ensures VM operators match interpreter behaviour on edge cases. |
| `invalid_collection_ops.yaml` | Error paths for object/set/array mutations with incorrect types. |
| `load_data_input.yaml` | `LoadData` and `LoadInput` instructions across nested/empty/undefined sources. |
| `loop_invalid_iteration.yaml` | Loop errors for non-iterables plus instruction-limit enforcement. |
| `null_undefined_handling.yaml` | Null/undefined behaviour across arithmetic, comparisons, indexing, loops, and comprehensions. |
| `object_operations.yaml` | Advanced object templates, dynamic keys, collisions, and validation. |
| `predefined.yaml` | Global `data` and `input` bindings, including nested access patterns. |
| `resource_limits.yaml` | Instruction counts, recursion depth, and other resource exhaustion scenarios. |
| `serialization.yaml` | Round-trip binary serialization for compiled programs covering all instruction families. |
| `set_operations.yaml` | Set creation, deduplication, membership checks, and nested values. |
| `type_errors.yaml` | Graceful error reporting for cross-family type mismatches. |
| `virtual_data_lookup.yaml` | `VirtualDataDocumentLookup` with base data, rule overrides, and invalid indices. |
## Loop Suites (`suites/loops/*.yaml`)
| Suite | Focus |
| --- | --- |
| `array_comprehensions.yaml` | Mapping, filtering, and edge cases for array comprehensions. |
| `empty.yaml` | Behaviour of every loop mode over empty collections (vacuous truth/falsehood). |
| `existential.yaml` | `some`-style (`Any`) quantification including early exits and complex predicates. |
| `loop_comprehension_interactions.yaml` | Interplay between nested loops and comprehensions emitting structured data. |
| `nested.yaml` | Mixed nesting patterns for loops and comprehensions with varying depth. |
| `nested_fixed.yaml` | Placeholder for future fixed-nesting scenarios (no cases yet). |
| `object_comprehensions.yaml` | Key/value emission, collision handling, and filtering in object comprehensions. |
| `set_comprehensions.yaml` | Deduplication and uniqueness guarantees in set comprehensions. |
| `universal.yaml` | `every`-style (`Every`) quantification, early failure, and vacuous truth cases. |
## Adding or Updating Suites
1. Place the new YAML file under `suites/` (or the relevant `suites/loops/` subdirectory).
2. Add a concise comment block at the top describing the intent and scenarios.
3. Update the tables above so the catalog stays accurate.
4. Run `cargo test --features rvm run_vm_test_file` to ensure the suite loads and all cases pass.
Keeping this README current makes it easier to discover coverage gaps and reason about the generated tests.

View File

@@ -0,0 +1,168 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Arithmetic Operations Test Suite
# Tests mathematical operations: Add, Sub, Mul, Div
# These instructions perform basic arithmetic on numeric values
cases:
- note: arithmetic_add
description: Test Add instruction
example_rego: "10 + 5" # Addition expression
literals:
- 10
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 10 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 5 into register 1
- "Add { dest: 2, left: 0, right: 1 }" # Add register 0 + register 1, store in register 2
- "Return { value: 2 }" # Return result from register 2
want_result: 15
- note: arithmetic_sub
description: Test Sub instruction
example_rego: "10 - 3" # Subtraction expression
literals:
- 10
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 10 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 3 into register 1
- "Sub { dest: 2, left: 0, right: 1 }" # Subtract register 1 from register 0, store in register 2
- "Return { value: 2 }" # Return result from register 2
want_result: 7
- note: arithmetic_mul
description: Test Mul instruction
example_rego: "4 * 6" # Multiplication expression
literals:
- 4
- 6
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 4 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 6 into register 1
- "Mul { dest: 2, left: 0, right: 1 }" # Multiply register 0 * register 1, store in register 2
- "Return { value: 2 }" # Return result from register 2
want_result: 24
- note: arithmetic_div
description: Test Div instruction
example_rego: "15 / 3" # Division expression
literals:
- 15
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 15 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 3 into register 1
- "Div { dest: 2, left: 0, right: 1 }" # Divide register 0 / register 1, store in register 2
- "Return { value: 2 }" # Return result from register 2
want_result: 5
- note: arithmetic_div_by_zero
description: Test Div by zero - undefined normally, error in strict mode
example_rego: "10 / 0"
literals:
- 10
- 0
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Div { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
want_error_strict: "Cannot divide"
- note: arithmetic_mod
description: Test Mod instruction
example_rego: "10 % 3"
literals:
- 10
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mod { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 1
- note: arithmetic_mod_by_zero
description: Test Mod by zero - undefined normally, error in strict mode
example_rego: "10 % 0"
literals:
- 10
- 0
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mod { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
want_error_strict: "Cannot modulo"
- note: arithmetic_mod_negative_operands
description: Test Mod with negative operands
example_rego: "-10 % 3"
literals:
- -10
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mod { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: -1
- note: arithmetic_mod_on_float_error
description: Test Mod on float - should error
example_rego: "10.5 % 3"
literals:
- 10.5
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mod { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "modulo on floating-point number"
- note: arithmetic_chained_operations
description: Test chained arithmetic operations (a + b) * c
example_rego: "(5 + 3) * 2"
literals:
- 5
- 3
- 2
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 5
- "Load { dest: 1, literal_idx: 1 }" # Load 3
- "Add { dest: 2, left: 0, right: 1 }" # 5 + 3 = 8
- "Load { dest: 3, literal_idx: 2 }" # Load 2
- "Mul { dest: 4, left: 2, right: 3 }" # 8 * 2 = 16
- "Return { value: 4 }"
want_result: 16
- note: arithmetic_float_precision
description: Test float arithmetic precision
example_rego: "0.1 + 0.2"
literals:
- 0.1
- 0.2
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 0.3
- note: arithmetic_large_numbers
description: Test arithmetic with large numbers
example_rego: "1000000 * 1000000"
literals:
- 1000000
- 1000000
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mul { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 1000000000000

View File

@@ -0,0 +1,47 @@
# Assertions Test Suite
# Exercises AssertNotUndefined behavior in isolation and inside loops.
cases:
- note: assert_not_undefined_passes
description: AssertNotUndefined succeeds when register has a value
literals:
- 42
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "AssertNotUndefined { register: 0 }"
- "Return { value: 0 }"
want_result: 42
- note: assert_not_undefined_fails
description: AssertNotUndefined triggers assertion error when register undefined
literals:
- "#undefined"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "AssertNotUndefined { register: 0 }"
- "Return { value: 0 }"
want_error: "Assertion failed"
- note: assert_not_undefined_inside_loop
description: AssertNotUndefined fails inside Every loop and exits with false result
literals:
- "#undefined"
instruction_params:
loop_params:
- mode: "Every"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 3
body_start: 5
loop_end: 7
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "LoopStart { params_index: 0 }"
- "Load { dest: 2, literal_idx: 0 }"
- "AssertNotUndefined { register: 2 }"
- "LoopNext { body_start: 5, loop_end: 7 }"
- "Return { value: 3 }"
want_result: false

View File

@@ -0,0 +1,32 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Basic VM Instructions Test Suite
# Tests fundamental instructions: Load, Move, Return
# These form the foundation for all other VM operations
cases:
- note: load_instruction
description: Test basic Load instruction
example_rego: "42" # Simple literal expression
literals:
- 42
- "hello"
- true
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 42 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal "hello" into register 1
- "Load { dest: 2, literal_idx: 2 }" # Load literal true into register 2
- "Return { value: 0 }" # Return value from register 0
want_result: 42
- note: move_instruction
description: Test Move instruction
example_rego: "x := 123; x" # Variable assignment and reference
literals:
- 123
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 123 into register 0 (x := 123)
- "Move { dest: 1, src: 0 }" # Move value from register 0 to register 1 (reference x)
- "Return { value: 1 }" # Return value from register 1
want_result: 123

View File

@@ -0,0 +1,44 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Boolean Literal Instructions Test Suite
# Validates that LoadBool behaves consistently with LoadTrue/LoadFalse
# and integrates correctly with logical instructions.
cases:
- note: load_bool_true
description: LoadBool true matches LoadTrue semantics
literals: []
instructions:
- "LoadBool { dest: 0, value: true }"
- "Return { value: 0 }"
want_result: true
- note: load_bool_false
description: LoadBool false matches LoadFalse semantics
literals: []
instructions:
- "LoadBool { dest: 0, value: false }"
- "Return { value: 0 }"
want_result: false
- note: load_bool_with_and
description: Combine LoadBool values using And instruction
literals: []
instructions:
- "LoadBool { dest: 0, value: true }"
- "LoadBool { dest: 1, value: false }"
- "And { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: false
- note: load_bool_with_or_not
description: Ensure LoadBool integrates with Or and Not
literals: []
instructions:
- "LoadBool { dest: 0, value: false }"
- "LoadBool { dest: 1, value: true }"
- "Or { dest: 2, left: 0, right: 1 }"
- "Not { dest: 3, operand: 2 }"
- "Return { value: 3 }"
want_result: false

View File

@@ -0,0 +1,524 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Builtin Functions Test Suite
# Tests the VM's builtin function call mechanism with various builtin functions
# Covers argument handling, return values, and error cases
cases:
# Basic Count Function Tests
- note: builtin_count_array
description: Test count builtin with array argument
example_rego: "count([1, 2, 3])"
literals:
- [1, 2, 3]
instruction_params:
builtin_infos:
- name: "count"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load [1, 2, 3] into register 0
- "BuiltinCall { params_index: 0 }" # Call count(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 3
- note: builtin_count_string
description: Test count builtin with string argument
example_rego: "count(\"hello\")"
literals:
- "hello"
instruction_params:
builtin_infos:
- name: "count"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load "hello" into register 0
- "BuiltinCall { params_index: 0 }" # Call count(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 5
- note: builtin_count_object
description: Test count builtin with object argument
example_rego: "count({\"a\": 1, \"b\": 2})"
literals:
- {"a": 1, "b": 2}
instruction_params:
builtin_infos:
- name: "count"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load object into register 0
- "BuiltinCall { params_index: 0 }" # Call count(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 2
- note: builtin_count_empty_array
description: Test count builtin with empty array
example_rego: "count([])"
literals:
- []
instruction_params:
builtin_infos:
- name: "count"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load empty array into register 0
- "BuiltinCall { params_index: 0 }" # Call count(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 0
# Max Function Tests
- note: builtin_max_array
description: Test max builtin with array argument
example_rego: "max([1, 5, 3])"
literals:
- [1, 5, 3]
instruction_params:
builtin_infos:
- name: "max"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load [1, 5, 3] into register 0
- "BuiltinCall { params_index: 0 }" # Call max(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 5
- note: builtin_max_empty_array
description: Test max builtin with empty array returns undefined
example_rego: "max([])"
literals:
- []
instruction_params:
builtin_infos:
- name: "max"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load empty array into register 0
- "BuiltinCall { params_index: 0 }" # Call max(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: "#undefined"
# Min Function Tests
- note: builtin_min_array
description: Test min builtin with array argument
example_rego: "min([1, 5, 3])"
literals:
- [1, 5, 3]
instruction_params:
builtin_infos:
- name: "min"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load [1, 5, 3] into register 0
- "BuiltinCall { params_index: 0 }" # Call min(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 1
# Sum Function Tests
- note: builtin_sum_array
description: Test sum builtin with numeric array
example_rego: "sum([1, 2, 3, 4])"
literals:
- [1, 2, 3, 4]
instruction_params:
builtin_infos:
- name: "sum"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load [1, 2, 3, 4] into register 0
- "BuiltinCall { params_index: 0 }" # Call sum(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 10
- note: builtin_sum_empty_array
description: Test sum builtin with empty array
example_rego: "sum([])"
literals:
- []
instruction_params:
builtin_infos:
- name: "sum"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load empty array into register 0
- "BuiltinCall { params_index: 0 }" # Call sum(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 0
# String Functions Tests
- note: builtin_upper_string
description: Test upper builtin function
example_rego: "upper(\"hello\")"
literals:
- "hello"
instruction_params:
builtin_infos:
- name: "upper"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load "hello" into register 0
- "BuiltinCall { params_index: 0 }" # Call upper(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: "HELLO"
- note: builtin_lower_string
description: Test lower builtin function
example_rego: "lower(\"WORLD\")"
literals:
- "WORLD"
instruction_params:
builtin_infos:
- name: "lower"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load "WORLD" into register 0
- "BuiltinCall { params_index: 0 }" # Call lower(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: "world"
# Multi-argument Builtin Tests
- note: builtin_contains_string
description: Test contains builtin with string arguments
example_rego: "contains(\"hello world\", \"world\")"
literals:
- "hello world"
- "world"
instruction_params:
builtin_infos:
- name: "contains"
num_args: 2
builtin_call_params:
- dest: 2
builtin_index: 0
args: [0, 1]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load "hello world" into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load "world" into register 1
- "BuiltinCall { params_index: 0 }" # Call contains(register[0], register[1]), result in register 2
- "Return { value: 2 }" # Return result
want_result: true
- note: builtin_contains_string_false
description: Test contains builtin with non-matching strings
example_rego: "contains(\"hello\", \"world\")"
literals:
- "hello"
- "world"
instruction_params:
builtin_infos:
- name: "contains"
num_args: 2
builtin_call_params:
- dest: 2
builtin_index: 0
args: [0, 1]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load "hello" into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load "world" into register 1
- "BuiltinCall { params_index: 0 }" # Call contains(register[0], register[1]), result in register 2
- "Return { value: 2 }" # Return result
want_result: false
# Array Function Tests
- note: builtin_sort_array
description: Test sort builtin with array
example_rego: "sort([3, 1, 4, 1, 5])"
literals:
- [3, 1, 4, 1, 5]
instruction_params:
builtin_infos:
- name: "sort"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load unsorted array into register 0
- "BuiltinCall { params_index: 0 }" # Call sort(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: [1, 1, 3, 4, 5]
# Type Function Tests
- note: builtin_type_string
description: Test type_name builtin with string
example_rego: "type_name(\"hello\")"
literals:
- "hello"
instruction_params:
builtin_infos:
- name: "type_name"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load "hello" into register 0
- "BuiltinCall { params_index: 0 }" # Call type_name(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: "string"
- note: builtin_type_number
description: Test type_name builtin with number
example_rego: "type_name(42)"
literals:
- 42
instruction_params:
builtin_infos:
- name: "type_name"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 42 into register 0
- "BuiltinCall { params_index: 0 }" # Call type_name(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: "number"
- note: builtin_type_array
description: Test type_name builtin with array
example_rego: "type_name([1, 2, 3])"
literals:
- [1, 2, 3]
instruction_params:
builtin_infos:
- name: "type_name"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load array into register 0
- "BuiltinCall { params_index: 0 }" # Call type_name(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: "array"
# Complex Builtin Chain Tests
- note: builtin_chained_operations
description: Test chaining multiple builtin calls
example_rego: "upper(lower(\"HELLO\"))"
literals:
- "HELLO"
instruction_params:
builtin_infos:
- name: "lower"
num_args: 1
- name: "upper"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
- dest: 2
builtin_index: 1
args: [1]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load "HELLO" into register 0
- "BuiltinCall { params_index: 0 }" # Call lower(register[0]), result in register 1
- "BuiltinCall { params_index: 1 }" # Call upper(register[1]), result in register 2
- "Return { value: 2 }" # Return final result
want_result: "HELLO"
# Number Function Tests
- note: builtin_abs_positive
description: Test abs builtin with positive number
example_rego: "abs(42)"
literals:
- 42
instruction_params:
builtin_infos:
- name: "abs"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 42 into register 0
- "BuiltinCall { params_index: 0 }" # Call abs(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 42
- note: builtin_abs_negative
description: Test abs builtin with negative number
example_rego: "abs(-42)"
literals:
- -42
instruction_params:
builtin_infos:
- name: "abs"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load -42 into register 0
- "BuiltinCall { params_index: 0 }" # Call abs(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: 42
# Set Function Tests - Commented out due to set literal parsing issues
# TODO: Add proper set tests once set literal parsing is fixed
# - note: builtin_union_sets
# description: Test union builtin with sets
# ...
# Error Handling Tests
- note: builtin_missing_function
description: Test calling non-existent builtin function
example_rego: "nonexistent_function(42)"
literals:
- 42
instruction_params:
builtin_infos:
- name: "nonexistent_function"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 42 into register 0
- "BuiltinCall { params_index: 0 }" # Call nonexistent_function(register[0]), should error
- "Return { value: 1 }" # Return result
want_error: "Missing builtin function: nonexistent_function"
# Test sets and union builtin
- note: "union([{1, 2}, {2, 3}]) should return {1, 2, 3}"
description: Test union builtin with set of sets
example_rego: "union([{1, 2}, {2, 3}])"
literals:
-
set!:
-
set!:
- 1
- 2
-
set!:
- 2
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "BuiltinCall { params_index: 0 }"
- "Return { value: 1 }"
instruction_params:
builtin_infos:
- name: "union"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
want_result:
set!:
- 1
- 2
- 3
# Boolean Functions
- note: builtin_is_boolean_true
description: Test is_boolean builtin with true value
example_rego: "is_boolean(true)"
literals:
- true
instruction_params:
builtin_infos:
- name: "is_boolean"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load true into register 0
- "BuiltinCall { params_index: 0 }" # Call is_boolean(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: true
- note: builtin_is_boolean_false
description: Test is_boolean builtin with false value
example_rego: "is_boolean(false)"
literals:
- false
instruction_params:
builtin_infos:
- name: "is_boolean"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load false into register 0
- "BuiltinCall { params_index: 0 }" # Call is_boolean(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: true
- note: builtin_is_boolean_number
description: Test is_boolean builtin with number value (should return false)
example_rego: "is_boolean(42)"
literals:
- 42
instruction_params:
builtin_infos:
- name: "is_boolean"
num_args: 1
builtin_call_params:
- dest: 1
builtin_index: 0
args: [0]
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 42 into register 0
- "BuiltinCall { params_index: 0 }" # Call is_boolean(register[0]), result in register 1
- "Return { value: 1 }" # Return result
want_result: false

View File

@@ -0,0 +1,76 @@
# CallRule Test Suite
# Validates rule caching, partial structures, defaults, and inconsistencies.
cases:
- note: call_rule_basic_cache
description: CallRule caches results after first evaluation
literals:
- {}
- 1
rule_infos:
- rule_type: Complete
definitions:
- [3]
rule_tree:
data:
test:
allow: 0
instructions:
- "CallRule { dest: 0, rule_index: 0 }"
- "CallRule { dest: 2, rule_index: 0 }"
- "Return { value: 2 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "RuleReturn {}"
want_result: 1
- note: call_rule_partial_object_default
description: Partial object rule returns object even when no fields defined
literals:
- {}
rule_infos:
- rule_type: PartialObject
definitions:
- [2]
instructions:
- "CallRule { dest: 0, rule_index: 0 }"
- "Return { value: 0 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "RuleReturn {}"
want_result: {}
- note: call_rule_default_literal
description: Default literal used when complete rule returns undefined
literals:
- "default"
rule_infos:
- rule_type: Complete
definitions:
- [2]
default_literal_index: 0
instructions:
- "CallRule { dest: 0, rule_index: 0 }"
- "Return { value: 0 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "RuleReturn {}"
want_result: "default"
- note: call_rule_inconsistency
description: Complete rule with inconsistent results returns undefined
literals:
- 1
- 2
rule_infos:
- rule_type: Complete
definitions:
- [2, 5]
instructions:
- "CallRule { dest: 0, rule_index: 0 }"
- "Return { value: 0 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "RuleReturn {}"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "RuleReturn {}"
want_result: "#undefined"

View File

@@ -0,0 +1,111 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Comparison Operations Test Suite
# Tests comparison instructions: Eq, Ne, Lt, Le, Gt, Ge
# These instructions compare values and produce boolean results
cases:
- note: comparison_eq
description: Test Eq instruction
example_rego: "5 == 5" # Equality comparison
literals:
- 5
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 5 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 5 into register 1
- "Eq { dest: 2, left: 0, right: 1 }" # Compare register 0 == register 1, store result in register 2
- "Return { value: 2 }" # Return boolean result from register 2
want_result: true
- note: comparison_eq_false
description: Test Eq instruction with false result
example_rego: "5 == 3" # Equality comparison (false case)
literals:
- 5
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 5 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 3 into register 1
- "Eq { dest: 2, left: 0, right: 1 }" # Compare register 0 == register 1, store result in register 2
- "Return { value: 2 }" # Return boolean result from register 2
want_result: false
- note: comparison_ne
description: Test Ne instruction
example_rego: "5 != 3" # Inequality comparison
literals:
- 5
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 5 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 3 into register 1
- "Ne { dest: 2, left: 0, right: 1 }" # Compare register 0 != register 1, store result in register 2
- "Return { value: 2 }" # Return boolean result from register 2
want_result: true
- note: comparison_lt
description: Test Lt instruction
example_rego: "3 < 5" # Less than comparison
literals:
- 3
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 3 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 5 into register 1
- "Lt { dest: 2, left: 0, right: 1 }" # Compare register 0 < register 1, store result in register 2
- "Return { value: 2 }" # Return boolean result from register 2
want_result: true
- note: comparison_le
description: Test Le instruction (less than or equal)
example_rego: "5 <= 10" # Less than or equal comparison
literals:
- 5
- 10
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 5 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 10 into register 1
- "Le { dest: 2, left: 0, right: 1 }" # Compare register 0 <= register 1, store result in register 2
- "Return { value: 2 }" # Return boolean result from register 2
want_result: true
- note: comparison_ge
description: Test Ge instruction (greater than or equal)
example_rego: "10 >= 5" # Greater than or equal comparison
literals:
- 10
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 10 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 5 into register 1
- "Ge { dest: 2, left: 0, right: 1 }" # Compare register 0 >= register 1, store result in register 2
- "Return { value: 2 }" # Return boolean result from register 2
want_result: true
- note: comparison_gt
description: Test Gt instruction
example_rego: "7 > 3" # Greater than comparison
literals:
- 7
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 7 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 3 into register 1
- "Gt { dest: 2, left: 0, right: 1 }" # Compare register 0 > register 1, store result in register 2
- "Return { value: 2 }" # Return boolean result from register 2
want_result: true
- note: comparison_ge_equal
description: Test Ge instruction with equal values
example_rego: "5 >= 5" # Greater than or equal comparison (equal case)
literals:
- 5
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load literal 5 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load literal 5 into register 1
- "Ge { dest: 2, left: 0, right: 1 }" # Compare register 0 >= register 1, store result in register 2
- "Return { value: 2 }" # Return boolean result from register 2
want_result: true

View File

@@ -0,0 +1,230 @@
# Complex VM Control Flow Suite
# Exercises deep nesting of heterogeneous loops, comprehensions, and rule calls.
cases:
- note: twenty_level_loop_maze
description: Twenty levels of mixed loop modes with embedded comprehension and rule call
literals:
- 0
- 1
instruction_params:
loop_params:
- mode: "ForEach"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 10
body_start: 5
loop_end: 55
- mode: "Any"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 11
body_start: 6
loop_end: 54
- mode: "Every"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 12
body_start: 7
loop_end: 53
- mode: "ForEach"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 13
body_start: 8
loop_end: 52
- mode: "Any"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 14
body_start: 9
loop_end: 51
- mode: "Every"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 15
body_start: 10
loop_end: 50
- mode: "ForEach"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 16
body_start: 11
loop_end: 49
- mode: "Any"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 17
body_start: 12
loop_end: 48
- mode: "Every"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 18
body_start: 13
loop_end: 47
- mode: "ForEach"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 19
body_start: 14
loop_end: 46
- mode: "Any"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 20
body_start: 15
loop_end: 45
- mode: "Every"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 21
body_start: 16
loop_end: 44
- mode: "ForEach"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 22
body_start: 17
loop_end: 43
- mode: "Any"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 23
body_start: 18
loop_end: 42
- mode: "Every"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 24
body_start: 19
loop_end: 41
- mode: "ForEach"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 25
body_start: 20
loop_end: 40
- mode: "Any"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 26
body_start: 21
loop_end: 39
- mode: "Every"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 27
body_start: 22
loop_end: 38
- mode: "ForEach"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 28
body_start: 23
loop_end: 37
- mode: "Any"
collection: 1
key_reg: 2
value_reg: 3
result_reg: 29
body_start: 24
loop_end: 36
- mode: "ForEach"
collection: 4
key_reg: 30
value_reg: 31
result_reg: 32
body_start: 28
loop_end: 31
comprehension_begin_params:
- mode: "Array"
collection_reg: 4
key_reg: 30
value_reg: 31
body_start: 28
comprehension_end: 31
rule_infos:
- rule_type: Complete
definitions:
- [56]
instructions:
- "ArrayNew { dest: 1 }"
- "Load { dest: 8, literal_idx: 1 }"
- "ArrayPush { arr: 1, value: 8 }"
- "Load { dest: 7, literal_idx: 0 }"
- "LoopStart { params_index: 0 }"
- "LoopStart { params_index: 1 }"
- "LoopStart { params_index: 2 }"
- "LoopStart { params_index: 3 }"
- "LoopStart { params_index: 4 }"
- "LoopStart { params_index: 5 }"
- "LoopStart { params_index: 6 }"
- "LoopStart { params_index: 7 }"
- "LoopStart { params_index: 8 }"
- "LoopStart { params_index: 9 }"
- "LoopStart { params_index: 10 }"
- "LoopStart { params_index: 11 }"
- "LoopStart { params_index: 12 }"
- "LoopStart { params_index: 13 }"
- "LoopStart { params_index: 14 }"
- "LoopStart { params_index: 15 }"
- "LoopStart { params_index: 16 }"
- "LoopStart { params_index: 17 }"
- "LoopStart { params_index: 18 }"
- "LoopStart { params_index: 19 }"
- "ArrayNew { dest: 4 }"
- "ArrayPush { arr: 4, value: 8 }"
- "ComprehensionBegin { params_index: 0 }"
- "LoopStart { params_index: 20 }"
- "Move { dest: 31, src: 8 }"
- "ComprehensionYield { value_reg: 31 }"
- "LoopNext { body_start: 28, loop_end: 31 }"
- "ComprehensionEnd"
- "Add { dest: 7, left: 7, right: 8 }"
- "CallRule { dest: 9, rule_index: 0 }"
- "Add { dest: 7, left: 7, right: 9 }"
- "LoopNext { body_start: 24, loop_end: 36 }"
- "LoopNext { body_start: 23, loop_end: 37 }"
- "LoopNext { body_start: 22, loop_end: 38 }"
- "LoopNext { body_start: 21, loop_end: 39 }"
- "LoopNext { body_start: 20, loop_end: 40 }"
- "LoopNext { body_start: 19, loop_end: 41 }"
- "LoopNext { body_start: 18, loop_end: 42 }"
- "LoopNext { body_start: 17, loop_end: 43 }"
- "LoopNext { body_start: 16, loop_end: 44 }"
- "LoopNext { body_start: 15, loop_end: 45 }"
- "LoopNext { body_start: 14, loop_end: 46 }"
- "LoopNext { body_start: 13, loop_end: 47 }"
- "LoopNext { body_start: 12, loop_end: 48 }"
- "LoopNext { body_start: 11, loop_end: 49 }"
- "LoopNext { body_start: 10, loop_end: 50 }"
- "LoopNext { body_start: 9, loop_end: 51 }"
- "LoopNext { body_start: 8, loop_end: 52 }"
- "LoopNext { body_start: 7, loop_end: 53 }"
- "LoopNext { body_start: 6, loop_end: 54 }"
- "LoopNext { body_start: 5, loop_end: 55 }"
- "Return { value: 7 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "RuleReturn {}"
want_result: 2

View File

@@ -0,0 +1,80 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Constructed Collections Test Suite
# Validates ArrayCreate and SetCreate behavior including undefined handling.
cases:
- note: array_create_basic
description: ArrayCreate assembles elements from registers
literals:
- 1
- 2
instruction_params:
array_create_params:
- dest: 3
elements: [0, 1, 2]
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "ArrayCreate { params_index: 0 }"
- "Return { value: 3 }"
want_result:
- 1
- 2
- 3
- note: array_create_with_undefined
description: ArrayCreate returns undefined if any source is undefined
literals:
- 1
- {}
- "missing"
instruction_params:
array_create_params:
- dest: 2
elements: [0, 1]
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 3, literal_idx: 1 }"
- "Load { dest: 4, literal_idx: 2 }"
- "Index { dest: 1, container: 3, key: 4 }"
- "ArrayCreate { params_index: 0 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: set_create_basic
description: SetCreate deduplicates values and collects registers
literals:
- 1
- 2
instruction_params:
set_create_params:
- dest: 3
elements: [0, 1, 2]
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Load { dest: 2, literal_idx: 0 }"
- "SetCreate { params_index: 0 }"
- "Return { value: 3 }"
want_result:
set!: [1, 2]
- note: set_create_with_undefined
description: SetCreate returns undefined if any source register is undefined
literals:
- {}
- "missing"
instruction_params:
set_create_params:
- dest: 3
elements: [0]
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 0, container: 1, key: 2 }"
- "SetCreate { params_index: 0 }"
- "Return { value: 3 }"
want_result: "#undefined"

View File

@@ -0,0 +1,115 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Control Flow Test Suite
# Tests conditional execution and branching patterns
# Focuses on AssertCondition and conditional logic without loops
cases:
- note: assert_condition_true
description: Test AssertCondition with true condition
example_rego: "x > 5; x := 10" # Simple condition that should succeed
literals:
- 10
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 10 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load 5 into register 1
- "Gt { dest: 2, left: 0, right: 1 }" # Check if 10 > 5, store result in register 2
- "AssertCondition { condition: 2 }" # Assert the condition (should succeed)
- "Return { value: 0 }" # Return the original value
want_result: 10
- note: assert_condition_false
description: Test AssertCondition with false condition
example_rego: "x > 15; x := 10" # Simple condition that should fail
literals:
- 10
- 15
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 10 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load 15 into register 1
- "Gt { dest: 2, left: 0, right: 1 }" # Check if 10 > 15, store result in register 2
- "AssertCondition { condition: 2 }" # Assert the condition (should fail)
- "Return { value: 0 }" # Return the original value (never reached)
want_result: "#undefined" # VM should return undefined for failed assertion
- note: complex_condition_and
description: Test complex AND condition
example_rego: "x > 5; x < 15; x := 10" # Multiple conditions (both must be true)
literals:
- 10
- 5
- 15
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 10 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load 5 into register 1
- "Load { dest: 2, literal_idx: 2 }" # Load 15 into register 2
- "Gt { dest: 3, left: 0, right: 1 }" # Check if 10 > 5, store result in register 3
- "Lt { dest: 4, left: 0, right: 2 }" # Check if 10 < 15, store result in register 4
- "And { dest: 5, left: 3, right: 4 }" # AND both conditions, store result in register 5
- "AssertCondition { condition: 5 }" # Assert the combined condition (should succeed)
- "Return { value: 0 }" # Return the original value
want_result: 10
- note: complex_condition_or
description: Test complex OR condition
example_rego: "x < 5; x > 15; x := 10" # Either condition can be true (both are false here)
literals:
- 10
- 5
- 15
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 10 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load 5 into register 1
- "Load { dest: 2, literal_idx: 2 }" # Load 15 into register 2
- "Lt { dest: 3, left: 0, right: 1 }" # Check if 10 < 5, store result in register 3
- "Gt { dest: 4, left: 0, right: 2 }" # Check if 10 > 15, store result in register 4
- "Or { dest: 5, left: 3, right: 4 }" # OR both conditions, store result in register 5
- "AssertCondition { condition: 5 }" # Assert the combined condition (should fail)
- "Return { value: 0 }" # Return the original value (never reached)
want_result: "#undefined" # VM should return undefined for failed assertion
- note: conditional_value_selection
description: Test conditional value selection
example_rego: "result := x > 10 ? x * 2 : x * 3; x := 15" # Conditional expression simulation
literals:
- 15
- 10
- 2
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load 15 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load 10 into register 1
- "Load { dest: 2, literal_idx: 2 }" # Load 2 into register 2
- "Load { dest: 3, literal_idx: 3 }" # Load 3 into register 3
- "Gt { dest: 4, left: 0, right: 1 }" # Check if 15 > 10, store result in register 4
- "Mul { dest: 5, left: 0, right: 2 }" # Compute 15 * 2, store in register 5
- "Mul { dest: 6, left: 0, right: 3 }" # Compute 15 * 3, store in register 6
# Simulate conditional selection (in real VM this would use conditional instructions)
- "AssertCondition { condition: 4 }" # Since condition is true, we proceed with first value
- "Return { value: 5 }" # Return x * 2 (30)
want_result: 30
- note: nested_conditions
description: Test nested conditional logic
example_rego: "x > 0; y > 0; z := x + y; z > 10; x := 8; y := 5" # Nested conditions with intermediate calculation
literals:
- 8
- 5
- 0
- 10
instructions:
- "Load { dest: 0, literal_idx: 0 }" # Load x=8 into register 0
- "Load { dest: 1, literal_idx: 1 }" # Load y=5 into register 1
- "Load { dest: 2, literal_idx: 2 }" # Load 0 into register 2
- "Load { dest: 3, literal_idx: 3 }" # Load 10 into register 3
- "Gt { dest: 4, left: 0, right: 2 }" # Check if x > 0, store result in register 4
- "AssertCondition { condition: 4 }" # Assert x > 0 (should succeed)
- "Gt { dest: 5, left: 1, right: 2 }" # Check if y > 0, store result in register 5
- "AssertCondition { condition: 5 }" # Assert y > 0 (should succeed)
- "Add { dest: 6, left: 0, right: 1 }" # Compute z = x + y, store in register 6
- "Gt { dest: 7, left: 6, right: 3 }" # Check if z > 10, store result in register 7
- "AssertCondition { condition: 7 }" # Assert z > 10 (should succeed: 13 > 10)
- "Return { value: 6 }" # Return z value (13)
want_result: 13

View File

@@ -0,0 +1,232 @@
# Comprehensive VM semantics regression suite
# Covers arithmetic, comparisons, loop modes, assertions, and collection helpers.
cases:
- note: arithmetic_ops
description: Verify primitive arithmetic instructions and array aggregation
literals:
- 8
- 2
instructions:
- "ArrayNew { dest: 5 }"
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "ArrayPush { arr: 5, value: 2 }"
- "Sub { dest: 3, left: 0, right: 1 }"
- "ArrayPush { arr: 5, value: 3 }"
- "Mul { dest: 4, left: 3, right: 1 }"
- "ArrayPush { arr: 5, value: 4 }"
- "Div { dest: 6, left: 0, right: 1 }"
- "ArrayPush { arr: 5, value: 6 }"
- "Mod { dest: 7, left: 0, right: 1 }"
- "ArrayPush { arr: 5, value: 7 }"
- "Return { value: 5 }"
want_result: [10, 6, 12, 4, 0]
- note: comparison_and_logic
description: Validate comparison, boolean, and negation instructions
literals:
- 5
- 5
- 3
instructions:
- "ArrayNew { dest: 11 }"
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Load { dest: 2, literal_idx: 2 }"
- "Eq { dest: 3, left: 0, right: 1 }"
- "ArrayPush { arr: 11, value: 3 }"
- "Ne { dest: 4, left: 0, right: 1 }"
- "ArrayPush { arr: 11, value: 4 }"
- "Lt { dest: 5, left: 2, right: 0 }"
- "ArrayPush { arr: 11, value: 5 }"
- "Ge { dest: 6, left: 0, right: 2 }"
- "ArrayPush { arr: 11, value: 6 }"
- "And { dest: 7, left: 3, right: 5 }"
- "ArrayPush { arr: 11, value: 7 }"
- "Not { dest: 8, operand: 4 }"
- "ArrayPush { arr: 11, value: 8 }"
- "Or { dest: 9, left: 4, right: 5 }"
- "ArrayPush { arr: 11, value: 9 }"
- "Return { value: 11 }"
want_result: [true, false, true, true, true, true, true]
- note: loop_any_short_circuit_success
description: LoopMode::Any should exit on first successful iteration
literals:
- 1
- 2
- 3
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 6
value_reg: 7
result_reg: 8
body_start: 9
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayPush { arr: 0, value: 3 }"
- "Load { dest: 4, literal_idx: 1 }"
- "LoopStart { params_index: 0 }"
- "Eq { dest: 5, left: 7, right: 4 }"
- "AssertCondition { condition: 5 }"
- "LoopNext { body_start: 9, loop_end: 11 }"
- "Return { value: 8 }"
want_result: true
- note: loop_any_all_fail
description: LoopMode::Any should remain false when no iteration succeeds
literals:
- 1
- 2
- 3
- 99
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 6
value_reg: 7
result_reg: 8
body_start: 9
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayPush { arr: 0, value: 3 }"
- "Load { dest: 4, literal_idx: 3 }"
- "LoopStart { params_index: 0 }"
- "Eq { dest: 5, left: 7, right: 4 }"
- "AssertCondition { condition: 5 }"
- "LoopNext { body_start: 9, loop_end: 11 }"
- "Return { value: 8 }"
want_result: false
- note: loop_every_exits_on_failure
description: LoopMode::Every stops at the first failed iteration and returns false
literals:
- 1
- 0
- 1
instruction_params:
loop_params:
- mode: "Every"
collection: 0
key_reg: 6
value_reg: 7
result_reg: 8
body_start: 10
loop_end: 14
instructions:
- "ArrayNew { dest: 0 }"
- "ArrayNew { dest: 9 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayPush { arr: 0, value: 3 }"
- "Load { dest: 4, literal_idx: 0 }"
- "LoopStart { params_index: 0 }"
- "ArrayPush { arr: 9, value: 7 }"
- "Eq { dest: 5, left: 7, right: 4 }"
- "AssertCondition { condition: 5 }"
- "LoopNext { body_start: 10, loop_end: 13 }"
- "ArrayNew { dest: 10 }"
- "ArrayPush { arr: 10, value: 8 }"
- "ArrayPush { arr: 10, value: 9 }"
- "Return { value: 10 }"
want_result:
- false
- [1, 0]
- note: loop_foreach_collects_successes
description: LoopMode::ForEach tracks successful iterations while visiting all elements
literals:
- 0
- 5
instruction_params:
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 6
value_reg: 7
result_reg: 8
body_start: 9
loop_end: 13
instructions:
- "ArrayNew { dest: 0 }"
- "ArrayNew { dest: 9 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 3 }"
- "LoopStart { params_index: 0 }"
- "Eq { dest: 4, left: 7, right: 3 }"
- "ArrayPush { arr: 9, value: 4 }"
- "AssertCondition { condition: 4 }"
- "LoopNext { body_start: 9, loop_end: 12 }"
- "ArrayNew { dest: 10 }"
- "ArrayPush { arr: 10, value: 8 }"
- "ArrayPush { arr: 10, value: 9 }"
- "Return { value: 10 }"
want_result:
- true
- [false, false, true]
- note: assert_condition_without_loop_errors
description: AssertCondition outside of a loop reports an assertion failure
literals:
- false
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "AssertCondition { condition: 0 }"
- "Return { value: 0 }"
want_error: "Assertion failed"
- note: contains_and_count_helpers
description: Contains and Count semantics across arrays, sets, and non-collections
literals:
- 1
- 2
- 9
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 2 }"
- "SetNew { dest: 3 }"
- "SetAdd { set: 3, value: 1 }"
- "SetAdd { set: 3, value: 2 }"
- "Contains { dest: 4, collection: 0, value: 1 }"
- "Contains { dest: 5, collection: 3, value: 2 }"
- "Load { dest: 6, literal_idx: 2 }"
- "Contains { dest: 7, collection: 3, value: 6 }"
- "Count { dest: 8, collection: 0 }"
- "Count { dest: 9, collection: 3 }"
- "Count { dest: 10, collection: 1 }"
- "ArrayNew { dest: 11 }"
- "ArrayPush { arr: 11, value: 4 }"
- "ArrayPush { arr: 11, value: 5 }"
- "ArrayPush { arr: 11, value: 7 }"
- "ArrayPush { arr: 11, value: 8 }"
- "ArrayPush { arr: 11, value: 9 }"
- "ArrayPush { arr: 11, value: 10 }"
- "Return { value: 11 }"
want_result: [true, true, false, 2, 2, "#undefined"]

View File

@@ -0,0 +1,76 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Data Structures Test Suite
# Tests instructions for working with arrays, objects, and sets
# These instructions create and manipulate complex data types
cases:
- note: array_operations
description: Test array creation and access
example_rego: "arr := [1, 2, 3]; arr[0]" # Array creation and indexing
literals:
- 1
- 2
- 3
- 0 # index
instructions:
- "ArrayNew { dest: 0 }" # Create empty array in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "ArrayPush { arr: 0, value: 2 }" # Push 2 to array
- "Load { dest: 3, literal_idx: 2 }" # Load 3 into register 3
- "ArrayPush { arr: 0, value: 3 }" # Push 3 to array
- "Load { dest: 4, literal_idx: 3 }" # Load index 0 into register 4
- "Index { dest: 5, container: 0, key: 4 }" # Access array[0], store in register 5
- "Return { value: 5 }" # Return the indexed value
want_result: 1
- note: object_operations
description: Test object creation and access
example_rego: "obj := {\"key1\": \"value1\", \"key2\": 42}; obj.key1" # Object creation and field access
literals:
- {}
- "key1"
- "value1"
- "key2"
- 42
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }" # Create empty object in register 0
- "Load { dest: 1, literal_idx: 1 }" # Load "key1" into register 1
- "Load { dest: 2, literal_idx: 2 }" # Load "value1" into register 2
- "ObjectSet { obj: 0, key: 1, value: 2 }" # Set obj["key1"] = "value1"
- "Load { dest: 3, literal_idx: 3 }" # Load "key2" into register 3
- "Load { dest: 4, literal_idx: 4 }" # Load 42 into register 4
- "ObjectSet { obj: 0, key: 3, value: 4 }" # Set obj["key2"] = 42
- "Load { dest: 5, literal_idx: 1 }" # Load "key1" again for lookup
- "Index { dest: 6, container: 0, key: 5 }" # Access obj["key1"], store in register 6
- "Return { value: 6 }" # Return the field value
want_result: "value1"
- note: set_operations
description: Test set creation and membership
example_rego: "s := {1, 2, 3}; 2 in s" # Set creation and membership test
literals:
- 1
- 2
- 3
instructions:
- "SetNew { dest: 0 }" # Create empty set in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "SetAdd { set: 0, value: 1 }" # Add 1 to set
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "SetAdd { set: 0, value: 2 }" # Add 2 to set
- "Load { dest: 3, literal_idx: 2 }" # Load 3 into register 3
- "SetAdd { set: 0, value: 3 }" # Add 3 to set
- "Load { dest: 4, literal_idx: 1 }" # Load 2 again for membership check
- "Contains { dest: 5, collection: 0, value: 4 }" # Check if 2 is in set, store result in register 5
- "Return { value: 5 }" # Return boolean membership result
want_result: true

View File

@@ -0,0 +1,278 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Deep Nesting Test Suite
# Tests 3+ levels of nested loops with various loop modes and comprehensions
# Verifies register allocation, stack pressure, and control flow correctness
cases:
- note: three_level_nested_any_every_foreach
description: 3-level nesting - Any inside Every inside ForEach
example_rego: |
[outer |
outer := [1, 2][_];
every mid in [1, 2]; some inner in [1, 2]; inner == mid
]
literals:
- 1
- 2
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 0
result_reg: 0
key_reg: 10
value_reg: 11
body_start: 7
comprehension_end: 27
loop_params:
- mode: "ForEach" # Outer loop for comprehension
collection: 5
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 7
loop_end: 27
- mode: "Every" # Middle loop
collection: 8
key_reg: 20
value_reg: 21
result_reg: 22
body_start: 13
loop_end: 24
- mode: "Any" # Inner loop
collection: 13
key_reg: 30
value_reg: 31
result_reg: 32
body_start: 19
loop_end: 22
instructions:
# Build outer collection [1, 2]
- "ArrayNew { dest: 5 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 5, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 5, value: 2 }"
- "ComprehensionBegin { params_index: 0 }"
- "LoopStart { params_index: 0 }" # ForEach outer
# Build middle collection [1, 2]
- "ArrayNew { dest: 8 }"
- "Load { dest: 3, literal_idx: 0 }"
- "ArrayPush { arr: 8, value: 3 }"
- "Load { dest: 4, literal_idx: 1 }"
- "ArrayPush { arr: 8, value: 4 }"
- "LoopStart { params_index: 1 }" # Every middle
# Build inner collection [1, 2]
- "ArrayNew { dest: 13 }"
- "Load { dest: 6, literal_idx: 0 }"
- "ArrayPush { arr: 13, value: 6 }"
- "Load { dest: 7, literal_idx: 1 }"
- "ArrayPush { arr: 13, value: 7 }"
- "LoopStart { params_index: 2 }" # Any inner
# Check condition: inner == mid
- "Eq { dest: 40, left: 31, right: 21 }"
- "AssertCondition { condition: 40 }"
- "LoopNext { body_start: 19, loop_end: 22 }"
# End Any loop - check result
- "AssertCondition { condition: 32 }"
- "LoopNext { body_start: 13, loop_end: 24 }"
# End Every loop - check result
- "AssertCondition { condition: 22 }"
- "ComprehensionYield { value_reg: 11 }"
- "LoopNext { body_start: 7, loop_end: 27 }"
- "ComprehensionEnd"
- "Return { value: 0 }"
want_result: [1, 2]
- note: four_level_nested_loops
description: 4-level nested loops - stress test for stack depth
example_rego: |
some a in [1]; some b in [2]; some c in [3]; some d in [4]; a + b + c + d == 10
literals:
- 1
- 2
- 3
- 4
- 10
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 4
loop_end: 29
- mode: "Any"
collection: 2
key_reg: 20
value_reg: 21
result_reg: 22
body_start: 8
loop_end: 27
- mode: "Any"
collection: 4
key_reg: 30
value_reg: 31
result_reg: 32
body_start: 12
loop_end: 25
- mode: "Any"
collection: 6
key_reg: 40
value_reg: 41
result_reg: 42
body_start: 16
loop_end: 23
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "LoopStart { params_index: 0 }" # Level 1
- "ArrayNew { dest: 2 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ArrayPush { arr: 2, value: 3 }"
- "LoopStart { params_index: 1 }" # Level 2
- "ArrayNew { dest: 4 }"
- "Load { dest: 5, literal_idx: 2 }"
- "ArrayPush { arr: 4, value: 5 }"
- "LoopStart { params_index: 2 }" # Level 3
- "ArrayNew { dest: 6 }"
- "Load { dest: 7, literal_idx: 3 }"
- "ArrayPush { arr: 6, value: 7 }"
- "LoopStart { params_index: 3 }" # Level 4
# Compute sum: a + b + c + d
- "Add { dest: 43, left: 11, right: 21 }"
- "Add { dest: 44, left: 43, right: 31 }"
- "Add { dest: 45, left: 44, right: 41 }"
- "Load { dest: 46, literal_idx: 4 }"
- "Eq { dest: 47, left: 45, right: 46 }"
- "AssertCondition { condition: 47 }"
- "LoopNext { body_start: 16, loop_end: 23 }"
- "AssertCondition { condition: 42 }"
- "LoopNext { body_start: 12, loop_end: 25 }"
- "AssertCondition { condition: 32 }"
- "LoopNext { body_start: 8, loop_end: 27 }"
- "AssertCondition { condition: 22 }"
- "LoopNext { body_start: 4, loop_end: 29 }"
- "Return { value: 12 }"
want_result: true
- note: comprehension_inside_nested_loop
description: Array comprehension inside 2-level nested loop
example_rego: |
[[y | y := inner[_]] |
outer := [[1, 2], [3, 4]][_];
inner := outer
]
literals:
- 1
- 2
- 3
- 4
instruction_params:
comprehension_begin_params:
- mode: "Array" # Outer comprehension
collection_reg: 0
key_reg: 10
value_reg: 11
body_start: 15
comprehension_end: 23
- mode: "Array" # Inner comprehension
collection_reg: 14
key_reg: 20
value_reg: 21
body_start: 18
comprehension_end: 20
loop_params:
- mode: "ForEach" # Outer loop
collection: 8
key_reg: 10
value_reg: 11
result_reg: 13
body_start: 15
loop_end: 23
- mode: "ForEach" # Inner loop for comprehension
collection: 12
key_reg: 20
value_reg: 21
result_reg: 22
body_start: 18
loop_end: 20
instructions:
# Build outer array [[1, 2], [3, 4]]
- "ArrayNew { dest: 8 }"
- "ArrayNew { dest: 1 }"
- "Load { dest: 2, literal_idx: 0 }"
- "ArrayPush { arr: 1, value: 2 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ArrayPush { arr: 1, value: 3 }"
- "ArrayPush { arr: 8, value: 1 }"
- "ArrayNew { dest: 4 }"
- "Load { dest: 5, literal_idx: 2 }"
- "ArrayPush { arr: 4, value: 5 }"
- "Load { dest: 6, literal_idx: 3 }"
- "ArrayPush { arr: 4, value: 6 }"
- "ArrayPush { arr: 8, value: 4 }"
- "ComprehensionBegin { params_index: 0 }" # Start outer comprehension
- "LoopStart { params_index: 0 }" # ForEach over outer array
- "Move { dest: 12, src: 11 }" # inner := outer
- "ComprehensionBegin { params_index: 1 }" # Start inner comprehension
- "LoopStart { params_index: 1 }" # ForEach over inner array
- "ComprehensionYield { value_reg: 21 }" # Yield y
- "LoopNext { body_start: 18, loop_end: 20 }"
- "ComprehensionEnd" # End inner comprehension
- "ComprehensionYield { value_reg: 14 }" # Yield inner comprehension result
- "LoopNext { body_start: 15, loop_end: 23 }"
- "ComprehensionEnd" # End outer comprehension
- "Return { value: 0 }"
want_result: [[1, 2], [3, 4]]
- note: register_pressure_nested_loops
description: Nested loops with 15+ active registers to test allocation
example_rego: |
some a in [1]; some b in [2]; a + b > 0
literals:
- 1
- 2
- 0
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 4
loop_end: 19
- mode: "Any"
collection: 2
key_reg: 20
value_reg: 21
result_reg: 22
body_start: 8
loop_end: 17
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "LoopStart { params_index: 0 }"
- "ArrayNew { dest: 2 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ArrayPush { arr: 2, value: 3 }"
- "LoopStart { params_index: 1 }"
# Use many registers to create pressure
- "Move { dest: 23, src: 11 }"
- "Move { dest: 24, src: 21 }"
- "Move { dest: 25, src: 23 }"
- "Move { dest: 26, src: 24 }"
- "Add { dest: 27, left: 25, right: 26 }"
- "Load { dest: 28, literal_idx: 2 }"
- "Gt { dest: 29, left: 27, right: 28 }"
- "AssertCondition { condition: 29 }"
- "LoopNext { body_start: 6, loop_end: 14 }"
- "AssertCondition { condition: 22 }"
- "LoopNext { body_start: 3, loop_end: 16 }"
- "Return { value: 12 }"
want_result: true

View File

@@ -0,0 +1,277 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Default Rules Infrastructure Test Suite
# Tests the VM infrastructure support for default rule evaluation
# These tests verify that the VM can properly handle complete rules with default fallbacks
cases:
- note: vm_default_rule_boolean_false
description: Test VM default rule evaluation with boolean false value
example_rego: "default allow := false; allow := true if { false }"
literals:
- false
- true
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 (false)
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 0 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load true result
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: false # Should return default value when condition fails
- note: vm_default_rule_boolean_true
description: Test VM default rule evaluation with boolean true value
example_rego: "default enabled := true; enabled := false if { false }"
literals:
- true
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 (true)
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 1 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load false result
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: true # Should return default value when condition fails
- note: vm_default_rule_string_value
description: Test VM default rule evaluation with string value
example_rego: "default message := \"default\"; message := \"success\" if { false }"
literals:
- "default"
- "success"
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 ("default")
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 2 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load success result
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: "default" # Should return default value when condition fails
- note: vm_default_rule_number_value
description: Test VM default rule evaluation with numeric value
example_rego: "default count := 0; count := 10 if { false }"
literals:
- 0
- 10
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 (0)
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 2 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load 10 result
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: 0 # Should return default value when condition fails
- note: vm_default_rule_array_value
description: Test VM default rule evaluation with array value
example_rego: "default items := [\"default\"]; items := [\"success\"] if { false }"
literals:
- ["default"]
- ["success"]
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 (["default"])
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 2 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load success array
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: ["default"] # Should return default value when condition fails
- note: vm_default_rule_object_value
description: Test VM default rule evaluation with object value
example_rego: "default config := {\"mode\": \"safe\"}; config := {\"mode\": \"fast\"} if { false }"
literals:
- {"mode": "safe"}
- {"mode": "fast"}
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 ({"mode": "safe"})
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 2 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load fast config
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result:
mode: "safe" # Should return default value when condition fails
- note: vm_default_rule_null_value
description: Test VM default rule evaluation with null value
example_rego: "default optional := null; optional := \"value\" if { false }"
literals:
- null
- "value"
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 (null)
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 2 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load string value
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: null # Should return default value when condition fails
- note: vm_default_rule_multiple_definitions_fail
description: Test VM default rule when multiple definitions all fail
example_rego: "default result := \"fallback\"; result := \"first\" if { false }; result := \"second\" if { false }"
literals:
- "fallback"
- "first"
- "second"
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2], [7]] # Two rule definitions
default_literal_index: 0 # Points to literal index 0 ("fallback")
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
# First definition
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 3 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load first result
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
# Second definition
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 4, literal_idx: 3 }" # Load false condition
- "AssertCondition { condition: 4 }" # Assert condition (will fail)
- "Load { dest: 5, literal_idx: 2 }" # Load second result
- "Move { dest: 1, src: 5 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: "fallback" # Should return default value when all definitions fail
- note: vm_default_rule_successful_condition
description: Test VM rule evaluation when condition succeeds (should not use default)
example_rego: "default allow := false; allow := true if { true }"
literals:
- false
- true
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 (false) - should not be used
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 1 }" # Load true condition
- "AssertCondition { condition: 2 }" # Assert condition (will succeed)
- "Load { dest: 3, literal_idx: 1 }" # Load true result
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: true # Should return successful rule result, not default
- note: vm_default_rule_complex_object
description: Test VM default rule with complex nested object
example_rego: "default settings := complex_default; settings := complex_success if { false }"
literals:
- {
"timeout": 30,
"retries": 3,
"features": {
"logging": true,
"monitoring": false
},
"endpoints": ["api1", "api2"]
}
- {
"timeout": 60,
"retries": 5,
"features": {
"logging": false,
"monitoring": true
},
"endpoints": ["api3", "api4"]
}
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
default_literal_index: 0 # Points to literal index 0 (complex default object)
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 2 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 1 }" # Load success object
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result:
timeout: 30
retries: 3
features:
logging: true
monitoring: false
endpoints: ["api1", "api2"] # Should return default complex object
- note: vm_no_default_rule_undefined
description: Test VM rule without default returns undefined when definition fails
example_rego: "allow := true if { false } # No default rule"
literals:
- true
- false
rule_infos:
- rule_type: "Complete"
definitions: [[2]] # Rule definition starts at instruction 2
# No default_literal_index - should return undefined
instructions:
- "CallRule { dest: 0, rule_index: 0 }" # Call the complete rule
- "Return { value: 0 }" # Return result
- "RuleInit { result_reg: 1, rule_index: 0 }" # Initialize rule execution
- "Load { dest: 2, literal_idx: 1 }" # Load false condition
- "AssertCondition { condition: 2 }" # Assert condition (will fail)
- "Load { dest: 3, literal_idx: 0 }" # Load true result
- "Move { dest: 1, src: 3 }" # Move result to result register
- "RuleReturn" # Return from rule
want_result: "#undefined" # Should return undefined when no default and definition fails

View File

@@ -0,0 +1,41 @@
# Destructuring Rules Test Suite
# Covers DestructuringSuccess control flow for rule parameters.
cases:
- note: destructuring_success_path
description: Destructuring block passes and body executes
literals:
- 1
rule_infos:
- rule_type: Complete
definitions:
- [4]
destructuring_blocks: [2]
instructions:
- "CallRule { dest: 0, rule_index: 0 }"
- "Return { value: 0 }"
- "Load { dest: 2, literal_idx: 0 }"
- "DestructuringSuccess {}"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "RuleReturn {}"
want_result: 1
- note: destructuring_failure_skips_body
description: Missing DestructuringSuccess causes undefined result
literals:
- 1
rule_infos:
- rule_type: Complete
definitions:
- [4]
destructuring_blocks: [2]
instructions:
- "CallRule { dest: 0, rule_index: 0 }"
- "Return { value: 0 }"
- "LoadFalse { dest: 2 }"
- "AssertCondition { condition: 2 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "RuleReturn {}"
want_result: "#undefined"

View File

@@ -0,0 +1,371 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Function Call Instructions Test Suite
# Tests the VM's function call mechanism with user-defined function rules
# Covers FunctionCall instruction, argument passing, and return values
cases:
# Basic Function Call Tests
- note: simple_function_call
description: Test basic function call instruction with one argument
example_rego: "add_ten(5) where add_ten(x) := x + 10"
literals:
- {}
- 5 # Argument value
- 10 # Constant 10 for addition
instruction_params:
object_create_params:
- dest: 6
template_literal_idx: 0
literal_key_fields: []
fields: []
function_call_params:
- func: 0 # Rule index for add_ten function (rule 0)
dest: 2 # Destination register for result
args: [1] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [3] # Entry point for add_ten function body (PC 3)
instructions:
- "Load { dest: 1, literal_idx: 1 }" # Load argument 5 into register 1
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 2 }" # Return result
# Function body starts at PC 3 (entry point)
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "Load { dest: 3, literal_idx: 2 }" # Load constant 10 into register 3
- "Add { dest: 0, left: 1, right: 3 }" # Add argument + 10 (result in register 0)
- "RuleReturn {}" # Return from function
want_result: 15
- note: function_call_multiple_args
description: Test function call with multiple arguments
example_rego: "add(7, 3) where add(x, y) := x + y"
literals:
- {}
- 0 # Rule index for add function
- 7 # First argument
- 3 # Second argument
instruction_params:
function_call_params:
- func: 0 # Register containing function rule index
dest: 3 # Destination register for result
args: [1, 2] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [5] # Entry point for add function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "Load { dest: 1, literal_idx: 2 }" # Load first argument
- "Load { dest: 2, literal_idx: 3 }" # Load second argument
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 3 }" # Return result
# Function body
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "Add { dest: 0, left: 1, right: 2 }" # Add arguments (result in register 0)
- "RuleReturn {}" # Return from function
want_result: 10
- note: function_call_no_args
description: Test function call with no arguments
example_rego: "get_constant() where get_constant() := 42"
literals:
- {}
- 0 # Rule index for get_constant function
- 42 # Constant value
instruction_params:
function_call_params:
- func: 0 # Register containing function rule index
dest: 1 # Destination register for result
args: [] # No arguments
rule_infos:
- rule_type: Complete
definitions:
- [3] # Entry point for get_constant function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 1 }" # Return result
# Function body
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "Load { dest: 0, literal_idx: 2 }" # Load constant 42 (result in register 0)
- "RuleReturn {}" # Return from function
want_result: 42
- note: function_call_with_multiplication
description: Test function that performs multiplication
example_rego: "square(6) where square(x) := x * x"
literals:
- {}
- 0 # Rule index for square function
- 6 # Argument value
instruction_params:
function_call_params:
- func: 0 # Register containing function rule index
dest: 2 # Destination register for result
args: [1] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [4] # Entry point for square function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "Load { dest: 1, literal_idx: 2 }" # Load argument 6
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 2 }" # Return result
# Function body
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "Mul { dest: 0, left: 1, right: 1 }" # Multiply x * x (result in register 0)
- "RuleReturn {}" # Return from function
want_result: 36
- note: nested_function_calls
description: Test nested function calls
example_rego: "double(add_one(5)) where double(x) := x * 2; add_one(x) := x + 1"
literals:
- {}
- 1 # Rule index for add_one function
- 0 # Rule index for double function
- 5 # Initial argument
- 1 # Constant 1
- 2 # Constant 2
instruction_params:
function_call_params:
- func: 1 # First call: add_one (rule index 1)
dest: 4 # Temporary result
args: [2] # Argument register
- func: 0 # Second call: double (rule index 0)
dest: 5 # Final result
args: [4] # Use result from first call
rule_infos:
- rule_type: Complete # double function
definitions:
- [10] # Entry point for double function body (updated)
- rule_type: Complete # add_one function
definitions:
- [6] # Entry point for add_one function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load add_one rule index
- "Load { dest: 1, literal_idx: 2 }" # Load double rule index
- "Load { dest: 2, literal_idx: 3 }" # Load argument 5
- "FunctionCall { params_index: 0 }" # Call add_one(5)
- "FunctionCall { params_index: 1 }" # Call double(result)
- "Return { value: 5 }" # Return final result
# add_one function body (starts at PC 6)
- "RuleInit { result_reg: 0, rule_index: 1 }" # Initialize result register for add_one
- "Load { dest: 3, literal_idx: 4 }" # Load constant 1
- "Add { dest: 0, left: 1, right: 3 }" # x + 1 (result in register 0)
- "RuleReturn {}" # Return result
# double function body (starts at PC 10)
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register for double
- "Load { dest: 3, literal_idx: 5 }" # Load constant 2
- "Mul { dest: 0, left: 1, right: 3 }" # x * 2 (result in register 0)
- "RuleReturn {}" # Return result
want_result: 12
- note: function_call_undefined_result
description: Test function call that returns undefined due to failed condition
example_rego: "safe_div(1, 0) where safe_div(x, y) := x / y if y != 0"
literals:
- {}
- 0 # Rule index for safe_div function
- 1 # Numerator
- 0 # Denominator (zero)
instruction_params:
function_call_params:
- func: 0 # Register containing function rule index
dest: 3 # Destination register for result
args: [1, 2] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [5] # Entry point for safe_div function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "Load { dest: 1, literal_idx: 2 }" # Load numerator
- "Load { dest: 2, literal_idx: 3 }" # Load denominator
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 3 }" # Return result
# Function body with condition that fails
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "LoadFalse { dest: 4 }" # Condition fails (simulated y == 0)
- "AssertCondition { condition: 4 }" # Assert fails, body fails
- "Div { dest: 0, left: 1, right: 2 }" # This won't execute
- "RuleReturn {}" # This won't execute
want_result: "#undefined"
- note: function_call_with_object_result
description: Test function call that returns an object
example_rego: "make_pair(1, 2) where make_pair(x, y) := {\"first\": x, \"second\": y}"
literals:
- {}
- 0 # Rule index for make_pair function
- 1 # First value
- 2 # Second value
- "first" # Key for first element
- "second" # Key for second element
instruction_params:
object_create_params:
- dest: 6
template_literal_idx: 0
literal_key_fields: []
fields: []
function_call_params:
- func: 0 # Register containing function rule index
dest: 5 # Destination register for result
args: [1, 2] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [5] # Entry point for make_pair function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "Load { dest: 1, literal_idx: 2 }" # Load first value
- "Load { dest: 2, literal_idx: 3 }" # Load second value
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 5 }" # Return result
# Function body
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 3, literal_idx: 4 }" # Load "first" key
- "ObjectSet { obj: 6, key: 3, value: 1 }" # Set first: x
- "Load { dest: 4, literal_idx: 5 }" # Load "second" key
- "ObjectSet { obj: 6, key: 4, value: 2 }" # Set second: y
- "Move { dest: 0, src: 6 }" # Move object to result register
- "RuleReturn {}" # Return object
want_result: {"first": 1, "second": 2}
- note: function_call_with_array_result
description: Test function call that returns an array
example_rego: "make_range(3, 5) where make_range(start, end) := [start, end]"
literals:
- {}
- 0 # Rule index for make_range function
- 3 # Start value
- 5 # End value
instruction_params:
function_call_params:
- func: 0 # Register containing function rule index
dest: 3 # Destination register for result
args: [1, 2] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [5] # Entry point for make_range function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "Load { dest: 1, literal_idx: 2 }" # Load start value
- "Load { dest: 2, literal_idx: 3 }" # Load end value
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 3 }" # Return result
# Function body
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "ArrayNew { dest: 4 }" # Create new array
- "ArrayPush { arr: 4, value: 1 }" # Push start value
- "ArrayPush { arr: 4, value: 2 }" # Push end value
- "Move { dest: 0, src: 4 }" # Move array to result register
- "RuleReturn {}" # Return array
want_result: [3, 5]
- note: function_call_with_comparison
description: Test function that performs comparison
example_rego: "max(7, 3) where max(x, y) := x if x >= y"
literals:
- {}
- 0 # Rule index for max function
- 7 # First value
- 3 # Second value
instruction_params:
function_call_params:
- func: 0 # Register containing function rule index
dest: 3 # Destination register for result
args: [1, 2] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [5] # Entry point for max function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "Load { dest: 1, literal_idx: 2 }" # Load first value (7)
- "Load { dest: 2, literal_idx: 3 }" # Load second value (3)
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 3 }" # Return result
# Function body: return x if x >= y
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "Ge { dest: 4, left: 1, right: 2 }" # x >= y
- "AssertCondition { condition: 4 }" # Assert condition
- "Move { dest: 0, src: 1 }" # Return x (move to result register)
- "RuleReturn {}" # Return result
want_result: 7
- note: function_call_three_args
description: Test function call with three arguments
example_rego: "sum_three(2, 3, 4) where sum_three(a, b, c) := a + b + c"
literals:
- {}
- 0 # Rule index for sum_three function
- 2 # First argument
- 3 # Second argument
- 4 # Third argument
instruction_params:
function_call_params:
- func: 0 # Register containing function rule index
dest: 4 # Destination register for result
args: [1, 2, 3] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [6] # Entry point for sum_three function body
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "Load { dest: 1, literal_idx: 2 }" # Load first argument (2)
- "Load { dest: 2, literal_idx: 3 }" # Load second argument (3)
- "Load { dest: 3, literal_idx: 4 }" # Load third argument (4)
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 4 }" # Return result
# Function body: a + b + c
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "Add { dest: 5, left: 1, right: 2 }" # a + b
- "Add { dest: 0, left: 5, right: 3 }" # (a + b) + c (result in register 0)
- "RuleReturn {}" # Return result
want_result: 9
- note: function_call_inconsistent_definitions
description: Test function with multiple definitions that produce different values (should fail)
example_rego: "f(5) where f(x) := x + 1; f(x) := x + 2"
literals:
- {}
- 0 # Rule index for f function
- 5 # Argument value
- 1 # Constant 1
- 2 # Constant 2
instruction_params:
function_call_params:
- func: 0 # Register containing function rule index
dest: 2 # Destination register for result
args: [1] # Argument registers
rule_infos:
- rule_type: Complete
definitions:
- [4] # First definition: x + 1
- [8] # Second definition: x + 2 (should produce different result)
entry_points:
"data.test.compute": [4, 8] # Multiple definitions for the same function
instructions:
- "Load { dest: 0, literal_idx: 1 }" # Load rule index
- "Load { dest: 1, literal_idx: 2 }" # Load argument (5)
- "FunctionCall { params_index: 0 }" # Call function
- "Return { value: 2 }" # Return result
# First definition: x + 1 (entry point 4)
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "Load { dest: 3, literal_idx: 3 }" # Load constant 1
- "Add { dest: 0, left: 1, right: 3 }" # x + 1 = 6 (result in register 0)
- "RuleReturn {}" # Return result
# Second definition: x + 2 (entry point 8)
- "RuleInit { result_reg: 0, rule_index: 0 }" # Initialize result register
- "Load { dest: 4, literal_idx: 4 }" # Load constant 2
- "Add { dest: 0, left: 1, right: 4 }" # x + 2 = 7 (result in register 0)
- "RuleReturn {}" # Return result
want_result: "#undefined"

View File

@@ -0,0 +1,14 @@
# Halt Instruction Test Suite
# Ensures Halt returns register 0 and ignores trailing instructions.
cases:
- note: halt_returns_register_zero
description: Halt ends execution and returns register 0
literals:
- 42
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Halt"
- "Load { dest: 1, literal_idx: 0 }"
- "Return { value: 1 }"
want_result: 42

View File

@@ -0,0 +1,137 @@
# HostAwait integration test suite
# Verifies host suspension across execution modes and optional run-to-completion fallbacks.
cases:
- note: host_await_single_response
description: Single HostAwait resumes with provided response in every execution mode
literals:
- "ping"
- "await-0"
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 3, literal_idx: 1 }"
- "HostAwait { dest: 2, arg: 1, id: 3 }"
- "ArrayPush { arr: 0, value: 2 }"
- "Return { value: 0 }"
host_await_responses:
- id: "await-0"
value: "pong"
want_result:
- "pong"
- note: host_await_multiple_responses
description: Multiple HostAwait instructions consume a queued sequence of responses
literals:
- 7
- "await-first"
- "await-second"
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 4, literal_idx: 1 }"
- "HostAwait { dest: 2, arg: 1, id: 4 }"
- "Load { dest: 5, literal_idx: 2 }"
- "HostAwait { dest: 3, arg: 2, id: 5 }"
- "ArrayPush { arr: 0, value: 2 }"
- "ArrayPush { arr: 0, value: 3 }"
- "Return { value: 0 }"
host_await_responses_run_to_completion:
- id: "await-first"
value: 42
- id: "await-second"
value: 43
host_await_responses_suspendable:
- id: "await-first"
value: 42
- id: "await-second"
value: 43
want_result:
- 42
- 43
- note: host_await_suspendable_only
description: Run-to-completion failure due to missing HostAwait response is ignored when flagged
literals:
- "payload"
- "await-single"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "HostAwait { dest: 1, arg: 0, id: 2 }"
- "Return { value: 1 }"
host_await_responses_suspendable:
- id: "await-single"
value: "resume-value"
ignore_run_to_completion_hostawait_failure: true
want_result: "resume-value"
- note: host_await_multiple_sequential
description: Three sequential HostAwait calls with different responses
literals:
- "first"
- "second"
- "third"
- "id-1"
- "id-2"
- "id-3"
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 10, literal_idx: 3 }"
- "HostAwait { dest: 2, arg: 1, id: 10 }"
- "ArrayPush { arr: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 1 }"
- "Load { dest: 11, literal_idx: 4 }"
- "HostAwait { dest: 4, arg: 3, id: 11 }"
- "ArrayPush { arr: 0, value: 4 }"
- "Load { dest: 5, literal_idx: 2 }"
- "Load { dest: 12, literal_idx: 5 }"
- "HostAwait { dest: 6, arg: 5, id: 12 }"
- "ArrayPush { arr: 0, value: 6 }"
- "Return { value: 0 }"
host_await_responses:
- id: "id-1"
value: "response-1"
- id: "id-2"
value: "response-2"
- id: "id-3"
value: "response-3"
want_result: ["response-1", "response-2", "response-3"]
- note: host_await_in_loop_body
description: HostAwait inside loop body - suspend/resume per iteration
literals:
- 1
- 2
- "id-1"
- "id-2"
instruction_params:
loop_params:
- mode: "ForEach"
collection: 5
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 7
loop_end: 11
instructions:
- "ArrayNew { dest: 5 }" # Collection [1, 2]
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 5, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 5, value: 2 }"
- "ArrayNew { dest: 0 }" # Result array
- "LoopStart { params_index: 0 }"
# HostAwait with dynamic ID based on loop value
- "Load { dest: 13, literal_idx: 2 }" # Load base ID
- "HostAwait { dest: 14, arg: 11, id: 13 }"
- "ArrayPush { arr: 0, value: 14 }"
- "LoopNext { body_start: 7, loop_end: 11 }"
- "Return { value: 0 }"
host_await_responses:
- id: "id-1"
value: "loop-response-1"
- id: "id-1"
value: "loop-response-2"
want_result: ["loop-response-1", "loop-response-2"]

View File

@@ -0,0 +1,28 @@
# Host Await Failures Test Suite
# Validates HostAwait error surfaces under different execution modes.
cases:
- note: host_await_missing_response
description: Run-to-completion mode errors when responses absent
literals:
- "request"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "HostAwait { dest: 1, arg: 0, id: 0 }"
- "Return { value: 1 }"
want_error: "HostAwait executed but no response provided"
- note: host_await_ignore_flag
description: ignore_run_to_completion_hostawait_failure guards missing responses
literals:
- "request"
- "response"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "HostAwait { dest: 1, arg: 0, id: 0 }"
- "Return { value: 1 }"
host_await_responses_suspendable:
- id: "request"
value: "response"
ignore_run_to_completion_hostawait_failure: true
want_result: "response"

View File

@@ -0,0 +1,241 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Indexed Access Test Suite
# Exercises literal indexing, chained indexing, and error paths.
cases:
- note: index_literal_success
description: IndexLiteral retrieves value when literal key exists
literals:
- { key: true }
- "key"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "LoadTrue { dest: 2 }"
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "IndexLiteral { dest: 3, container: 0, literal_idx: 1 }"
- "Return { value: 3 }"
want_result: true
- note: index_literal_bad_literal
description: IndexLiteral with invalid literal index triggers error
literals:
- {}
instructions:
- "ObjectCreate { params_index: 0 }"
- "IndexLiteral { dest: 1, container: 0, literal_idx: 99 }"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
want_error: "Literal index 99 out of bounds"
- note: chained_index_mixed_path
description: ChainedIndex handles literal and register path components
literals:
- {}
- "outer"
- "inner"
- "value"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
chained_index_params:
- dest: 5
root: 0
path_components:
- literal_idx: 1
- register: 3
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 3, literal_idx: 2 }" # inner
- "Load { dest: 4, literal_idx: 3 }" # value
- "Load { dest: 2, literal_idx: 0 }" # nested object builder
- "ObjectSet { obj: 2, key: 3, value: 4 }"
- "Load { dest: 1, literal_idx: 1 }" # outer
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "ChainedIndex { params_index: 0 }"
- "Return { value: 5 }"
want_result: "value"
- note: chained_index_undefined_propagation
description: ChainedIndex yields undefined when intermediate missing
literals:
- {}
- "missing"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
chained_index_params:
- dest: 2
root: 0
path_components:
- literal_idx: 1
- literal_idx: 1
instructions:
- "ObjectCreate { params_index: 0 }"
- "ChainedIndex { params_index: 0 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: chained_index_5_components
description: ChainedIndex with 5 path components
example_rego: "data.a.b.c.d.e"
literals:
- {}
- "a"
- "b"
- "c"
- "d"
- "e"
- "final_value"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
chained_index_params:
- dest: 10
root: 0
path_components:
- literal_idx: 1 # a
- literal_idx: 2 # b
- literal_idx: 3 # c
- literal_idx: 4 # d
- literal_idx: 5 # e
instructions:
- "ObjectCreate { params_index: 0 }" # r0 = {}
# Build nested structure: {a: {b: {c: {d: {e: "final_value"}}}}}
- "Load { dest: 1, literal_idx: 0 }" # innermost object
- "Load { dest: 2, literal_idx: 5 }" # key "e"
- "Load { dest: 3, literal_idx: 6 }" # value "final_value"
- "ObjectSet { obj: 1, key: 2, value: 3 }" # {e: "final_value"}
- "Load { dest: 4, literal_idx: 0 }" # d level object
- "Load { dest: 5, literal_idx: 4 }" # key "d"
- "ObjectSet { obj: 4, key: 5, value: 1 }" # {d: {e: ...}}
- "Load { dest: 6, literal_idx: 0 }" # c level object
- "Load { dest: 7, literal_idx: 3 }" # key "c"
- "ObjectSet { obj: 6, key: 7, value: 4 }" # {c: {d: ...}}
- "Load { dest: 8, literal_idx: 0 }" # b level object
- "Load { dest: 9, literal_idx: 2 }" # key "b"
- "ObjectSet { obj: 8, key: 9, value: 6 }" # {b: {c: ...}}
- "Load { dest: 11, literal_idx: 1 }" # key "a"
- "ObjectSet { obj: 0, key: 11, value: 8 }" # {a: {b: ...}}
- "ChainedIndex { params_index: 0 }"
- "Return { value: 10 }"
want_result: "final_value"
- note: chained_index_all_registers
description: ChainedIndex with all register components (no literals)
example_rego: "obj[key1][key2]"
literals:
- {}
- "level1"
- "level2"
- "result"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
chained_index_params:
- dest: 10
root: 0
path_components:
- register: 5 # key1
- register: 6 # key2
instructions:
- "ObjectCreate { params_index: 0 }" # r0 = {}
# Build structure: {level1: {level2: "result"}}
- "Load { dest: 1, literal_idx: 0 }" # inner object
- "Load { dest: 2, literal_idx: 2 }" # "level2"
- "Load { dest: 3, literal_idx: 3 }" # "result"
- "ObjectSet { obj: 1, key: 2, value: 3 }" # {level2: "result"}
- "Load { dest: 4, literal_idx: 1 }" # "level1"
- "ObjectSet { obj: 0, key: 4, value: 1 }" # {level1: {...}}
# Set up dynamic keys in registers
- "Load { dest: 5, literal_idx: 1 }" # key1 = "level1"
- "Load { dest: 6, literal_idx: 2 }" # key2 = "level2"
- "ChainedIndex { params_index: 0 }"
- "Return { value: 10 }"
want_result: "result"
- note: index_with_null_key
description: Index with null key returns undefined
example_rego: "obj[null]"
literals:
- {"key": "value"}
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadNull { dest: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: index_with_undefined_key
description: Index with undefined key returns undefined
example_rego: "obj[undefined_var]"
literals:
- {"key": "value"}
instructions:
- "Load { dest: 0, literal_idx: 0 }"
# r1 is undefined (never loaded)
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: index_with_boolean_key
description: Index with boolean key
example_rego: "obj[true]"
literals:
- {true: "bool_value", "regular": "string_value"}
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadTrue { dest: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "bool_value"
- note: index_with_empty_string_key
description: Index with empty string key
example_rego: "obj[\"\"]"
literals:
- {"": "empty_key_value", "other": "other_value"}
- ""
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "empty_key_value"
- note: index_with_number_key_on_object
description: Index object with number key
example_rego: "obj[42]"
literals:
- {42: "number_value", "str": "string_value"}
- 42
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "number_value"

View File

@@ -0,0 +1,432 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Integration Scenarios Test Suite
# Tests real-world Rego policy patterns
# Covers RBAC, filtering, transforms, and complex policy workflows
cases:
- note: rbac_admin_check
description: Role-based access control - check admin role
example_rego: "allow { user.roles[_] == \"admin\" }"
literals:
- {"roles": ["user", "admin", "developer"]}
- "roles"
- "admin"
instruction_params:
loop_params:
- mode: "Any"
collection: 2
key_reg: 3
value_reg: 4
result_reg: 6
body_start: 5
loop_end: 8
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Load { dest: 5, literal_idx: 2 }"
- "LoopStart { params_index: 0 }"
- "Eq { dest: 7, left: 4, right: 5 }"
- "AssertCondition { condition: 7 }"
- "LoopNext { body_start: 5, loop_end: 8 }"
- "Return { value: 6 }"
want_result: true
- note: rbac_no_matching_role
description: RBAC check fails when role not present
example_rego: "allow { user.roles[_] == \"superadmin\" }"
literals:
- {"roles": ["user", "developer"]}
- "roles"
- "superadmin"
instruction_params:
loop_params:
- mode: "Any"
collection: 2
key_reg: 3
value_reg: 4
result_reg: 6
body_start: 5
loop_end: 8
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Load { dest: 5, literal_idx: 2 }"
- "LoopStart { params_index: 0 }"
- "Eq { dest: 7, left: 4, right: 5 }"
- "AssertCondition { condition: 7 }"
- "LoopNext { body_start: 5, loop_end: 8 }"
- "Return { value: 6 }"
want_result: false
- note: filtering_by_owner
description: Filter resources by owner ID
example_rego: "[x | x = resources[_]; x.owner == user.id]"
literals:
- [{"name": "res1", "owner": "user123"}, {"name": "res2", "owner": "user456"}, {"name": "res3", "owner": "user123"}]
- {"id": "user123"}
- "owner"
- "id"
instruction_params:
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 11
body_start: 4
loop_end: 12
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "ArrayNew { dest: 8 }"
- "Load { dest: 9, literal_idx: 1 }"
- "LoopStart { params_index: 0 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Index { dest: 4, container: 2, key: 3 }"
- "Load { dest: 5, literal_idx: 3 }"
- "Index { dest: 6, container: 9, key: 5 }"
- "Eq { dest: 7, left: 4, right: 6 }"
- "AssertCondition { condition: 7 }"
- "ArrayPush { arr: 8, value: 2 }"
- "LoopNext { body_start: 4, loop_end: 12 }"
- "Return { value: 8 }"
want_result: [{"name": "res1", "owner": "user123"}, {"name": "res3", "owner": "user123"}]
- note: filtering_empty_result
description: Filter returns empty array when no matches
example_rego: "[x | x = resources[_]; x.owner == \"nonexistent\"]"
literals:
- [{"name": "res1", "owner": "user123"}, {"name": "res2", "owner": "user456"}]
- "owner"
- "nonexistent"
instruction_params:
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 8
body_start: 4
loop_end: 10
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "ArrayNew { dest: 7 }"
- "Load { dest: 5, literal_idx: 2 }"
- "LoopStart { params_index: 0 }"
- "Load { dest: 3, literal_idx: 1 }"
- "Index { dest: 4, container: 2, key: 3 }"
- "Eq { dest: 6, left: 4, right: 5 }"
- "AssertCondition { condition: 6 }"
- "ArrayPush { arr: 7, value: 2 }"
- "LoopNext { body_start: 4, loop_end: 10 }"
- "Return { value: 7 }"
want_result: []
- note: transform_multiply_values
description: Transform values by multiplying above threshold
example_rego: "{k: v * 2 | v = data.metrics[k]; v > threshold}"
literals:
- {"cpu": 50, "memory": 80, "disk": 30}
- 40
- 2
- {}
instruction_params:
object_create_params:
- dest: 4
template_literal_idx: 3
literal_key_fields: []
fields: []
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 9
body_start: 4
loop_end: 10
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ObjectCreate { params_index: 0 }"
- "LoopStart { params_index: 0 }"
- "Gt { dest: 5, left: 2, right: 3 }"
- "AssertCondition { condition: 5 }"
- "Load { dest: 7, literal_idx: 2 }"
- "Mul { dest: 8, left: 2, right: 7 }"
- "ObjectSet { obj: 4, key: 1, value: 8 }"
- "LoopNext { body_start: 4, loop_end: 10 }"
- "Return { value: 4 }"
want_result: {"cpu": 100, "memory": 160}
- note: transform_all_values
description: Transform all values in map
example_rego: "{k: v + 10 | v = data[k]}"
literals:
- {"a": 1, "b": 2, "c": 3}
- 10
- {}
instruction_params:
object_create_params:
- dest: 4
template_literal_idx: 2
literal_key_fields: []
fields: []
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 6
body_start: 4
loop_end: 7
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ObjectCreate { params_index: 0 }"
- "LoopStart { params_index: 0 }"
- "Add { dest: 5, left: 2, right: 3 }"
- "ObjectSet { obj: 4, key: 1, value: 5 }"
- "LoopNext { body_start: 4, loop_end: 7 }"
- "Return { value: 4 }"
want_result: {"a": 11, "b": 12, "c": 13}
- note: nested_filtering_and_transform
description: Filter then transform (chained operations)
example_rego: "[x * 2 | x = numbers[_]; x > 5]"
literals:
- [3, 7, 4, 9, 2, 8]
- 5
- 2
instruction_params:
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 6
body_start: 5
loop_end: 10
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "ArrayNew { dest: 5 }"
- "Load { dest: 9, literal_idx: 1 }"
- "Load { dest: 10, literal_idx: 2 }"
- "LoopStart { params_index: 0 }"
- "Gt { dest: 3, left: 2, right: 9 }"
- "AssertCondition { condition: 3 }"
- "Mul { dest: 4, left: 2, right: 10 }"
- "ArrayPush { arr: 5, value: 4 }"
- "LoopNext { body_start: 5, loop_end: 10 }"
- "Return { value: 5 }"
want_result: [14, 18, 16]
- note: multi_field_validation
description: Validate multiple fields meet criteria
example_rego: "valid { user.age >= 18; user.verified == true; user.status == \"active\" }"
literals:
- {"age": 25, "verified": true, "status": "active"}
- "age"
- 18
- "verified"
- "status"
- "active"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
# Check age >= 18
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Ge { dest: 4, left: 2, right: 3 }"
- "Load { dest: 5, literal_idx: 3 }"
- "Index { dest: 6, container: 0, key: 5 }"
- "LoadTrue { dest: 7 }"
- "Eq { dest: 8, left: 6, right: 7 }"
- "And { dest: 9, left: 4, right: 8 }"
- "Load { dest: 10, literal_idx: 4 }"
- "Index { dest: 11, container: 0, key: 10 }"
- "Load { dest: 12, literal_idx: 5 }"
- "Eq { dest: 13, left: 11, right: 12 }"
- "And { dest: 14, left: 9, right: 13 }"
- "Return { value: 14 }"
want_result: true
- note: multi_field_validation_failure
description: Multi-field validation fails when one criterion not met
example_rego: "valid { user.age >= 18; user.verified == true; user.status == \"active\" }"
literals:
- {"age": 25, "verified": false, "status": "active"}
- "age"
- 18
- "verified"
- "status"
- "active"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
# Check age >= 18
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Ge { dest: 4, left: 2, right: 3 }"
- "Load { dest: 5, literal_idx: 3 }"
- "Index { dest: 6, container: 0, key: 5 }"
- "LoadTrue { dest: 7 }"
- "Eq { dest: 8, left: 6, right: 7 }"
- "And { dest: 9, left: 4, right: 8 }"
- "Load { dest: 10, literal_idx: 4 }"
- "Index { dest: 11, container: 0, key: 10 }"
- "Load { dest: 12, literal_idx: 5 }"
- "Eq { dest: 13, left: 11, right: 12 }"
- "And { dest: 14, left: 9, right: 13 }"
- "Return { value: 14 }"
want_result: false
- note: set_membership_check
description: Check if value is in allowed set
example_rego: "allowed { input.action in {\"read\", \"write\", \"delete\"} }"
literals:
- {"action": "read"}
- "action"
- "read"
- "write"
- "delete"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
# Create allowed set
- "SetNew { dest: 3 }"
- "Load { dest: 4, literal_idx: 2 }"
- "SetAdd { set: 3, value: 4 }"
- "Load { dest: 5, literal_idx: 3 }"
- "SetAdd { set: 3, value: 5 }"
- "Load { dest: 6, literal_idx: 4 }"
- "SetAdd { set: 3, value: 6 }"
# Check membership
- "Contains { dest: 7, collection: 3, value: 2 }"
- "Return { value: 7 }"
want_result: true
- note: set_membership_denied
description: Check fails when value not in allowed set
example_rego: "allowed { input.action in {\"read\", \"write\", \"delete\"} }"
literals:
- {"action": "execute"}
- "action"
- "read"
- "write"
- "delete"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
# Create allowed set
- "SetNew { dest: 3 }"
- "Load { dest: 4, literal_idx: 2 }"
- "SetAdd { set: 3, value: 4 }"
- "Load { dest: 5, literal_idx: 3 }"
- "SetAdd { set: 3, value: 5 }"
- "Load { dest: 6, literal_idx: 4 }"
- "SetAdd { set: 3, value: 6 }"
# Check membership
- "Contains { dest: 7, collection: 3, value: 2 }"
- "Return { value: 7 }"
want_result: false
- note: aggregation_count
description: Count items matching condition
example_rego: "count([x | x = items[_]; x.status == \"active\"])"
literals:
- [{"id": 1, "status": "active"}, {"id": 2, "status": "inactive"}, {"id": 3, "status": "active"}]
- "status"
- "active"
instruction_params:
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 8
body_start: 4
loop_end: 10
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "ArrayNew { dest: 6 }"
- "Load { dest: 9, literal_idx: 2 }"
- "LoopStart { params_index: 0 }"
- "Load { dest: 3, literal_idx: 1 }"
- "Index { dest: 4, container: 2, key: 3 }"
- "Eq { dest: 5, left: 4, right: 9 }"
- "AssertCondition { condition: 5 }"
- "ArrayPush { arr: 6, value: 2 }"
- "LoopNext { body_start: 4, loop_end: 10 }"
- "Return { value: 6 }"
want_result: [{"id": 1, "status": "active"}, {"id": 3, "status": "active"}]
- note: hierarchical_permission_check
description: Check nested permission structure
example_rego: "allow { data.permissions[input.user][input.resource] == \"allow\" }"
literals:
- {"permissions": {"alice": {"doc1": "allow", "doc2": "deny"}, "bob": {"doc1": "deny"}}}
- {"user": "alice", "resource": "doc1"}
- "permissions"
- "user"
- "resource"
- "allow"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
# Load permissions
- "Load { dest: 2, literal_idx: 2 }"
- "Index { dest: 3, container: 0, key: 2 }"
# Load user
- "Load { dest: 4, literal_idx: 3 }"
- "Index { dest: 5, container: 1, key: 4 }"
# Index permissions by user
- "Index { dest: 6, container: 3, key: 5 }"
# Load resource
- "Load { dest: 7, literal_idx: 4 }"
- "Index { dest: 8, container: 1, key: 7 }"
# Index user permissions by resource
- "Index { dest: 9, container: 6, key: 8 }"
# Check if "allow"
- "Load { dest: 10, literal_idx: 5 }"
- "Eq { dest: 11, left: 9, right: 10 }"
- "Return { value: 11 }"
want_result: true
- note: default_value_pattern
description: Provide default value when path undefined
example_rego: "timeout := data.config.timeout; timeout == 30 if not data.config.timeout"
literals:
- {}
- "config"
- "timeout"
- 30
instruction_params:
loop_params:
- mode: "Any"
collection: 7
key_reg: 8
value_reg: 9
result_reg: 10
body_start: 10
loop_end: 13
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Index { dest: 4, container: 2, key: 3 }"
- "Load { dest: 5, literal_idx: 3 }"
- "Contains { dest: 6, collection: 2, value: 3 }"
- "ArrayNew { dest: 7 }"
- "ArrayPush { arr: 7, value: 6 }"
- "LoopStart { params_index: 0 }"
- "AssertCondition { condition: 9 }"
- "Move { dest: 5, src: 4 }"
- "LoopNext { body_start: 10, loop_end: 13 }"
- "Return { value: 5 }"
want_result: 30

View File

@@ -0,0 +1,351 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Interpreter Operator Compatibility Test Suite
# Tests that VM operators behave exactly like interpreter operators
# Focuses on edge cases like undefined value handling, division by zero, etc.
cases:
# Undefined Value Arithmetic Tests
- note: undefined_add
description: Test addition with undefined value
example_rego: "input.nonexistent + 5"
input: {} # Empty input to create undefined access
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }" # Load input into register 0
- "Load { dest: 1, literal_idx: 0 }" # Load string "nonexistent" for indexing
- "Load { dest: 2, literal_idx: 1 }" # Load 5 into register 2
- "Index { dest: 3, container: 0, key: 1 }" # Access input.nonexistent (undefined)
- "Add { dest: 4, left: 3, right: 2 }" # undefined + 5
- "Return { value: 4 }"
want_result: "#undefined"
- note: undefined_sub
description: Test subtraction with undefined value
example_rego: "input.nonexistent - 5"
input: {}
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Sub { dest: 4, left: 3, right: 2 }"
- "Return { value: 4 }"
want_result: "#undefined"
- note: undefined_mul
description: Test multiplication with undefined value
example_rego: "input.nonexistent * 5"
input: {}
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Mul { dest: 4, left: 3, right: 2 }"
- "Return { value: 4 }"
want_result: "#undefined"
# Division by Zero Tests
- note: division_by_zero
description: Test division by zero returns undefined (non-strict mode)
example_rego: "5 / 0"
literals:
- 5
- 0
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Div { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: modulo_by_zero
description: Test modulo by zero returns undefined (non-strict mode)
example_rego: "5 % 0"
literals:
- 5
- 0
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mod { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
# Modulo Float Tests
- note: modulo_float
description: Test modulo with floating point numbers (should error)
example_rego: "5.5 % 2"
literals:
- 5.5
- 2
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mod { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "modulo on floating-point number"
# Undefined Comparison Tests
- note: undefined_eq
description: Test equality comparison with undefined value
example_rego: "input.nonexistent == 5"
input: {}
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Eq { dest: 4, left: 3, right: 2 }"
- "Return { value: 4 }"
want_result: "#undefined"
- note: undefined_ne
description: Test inequality comparison with undefined value
example_rego: "input.nonexistent != 5"
input: {}
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Ne { dest: 4, left: 3, right: 2 }"
- "Return { value: 4 }"
want_result: "#undefined"
- note: undefined_lt
description: Test less than comparison with undefined value
example_rego: "input.nonexistent < 5"
input: {}
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Lt { dest: 4, left: 3, right: 2 }"
- "Return { value: 4 }"
want_result: "#undefined"
- note: undefined_le
description: Test less than or equal comparison with undefined value
example_rego: "input.nonexistent <= 5"
input: {}
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Le { dest: 4, left: 3, right: 2 }"
- "Return { value: 4 }"
want_result: "#undefined"
- note: undefined_gt
description: Test greater than comparison with undefined value
example_rego: "input.nonexistent > 5"
input: {}
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Gt { dest: 4, left: 3, right: 2 }"
- "Return { value: 4 }"
want_result: "#undefined"
- note: undefined_ge
description: Test greater than or equal comparison with undefined value
example_rego: "input.nonexistent >= 5"
input: {}
literals:
- "nonexistent"
- 5
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Ge { dest: 4, left: 3, right: 2 }"
- "Return { value: 4 }"
want_result: "#undefined"
# Number Type Precision Tests
- note: number_add_precision
description: Test Number type addition preserves precision
example_rego: "1.1 + 2.2"
literals:
- 1.1
- 2.2
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 3.3
- note: number_sub_precision
description: Test Number type subtraction preserves precision
example_rego: "5.5 - 2.2"
literals:
- 5.5
- 2.2
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Sub { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 3.3
- note: number_mul_precision
description: Test Number type multiplication preserves precision
example_rego: "2.5 * 4.0"
literals:
- 2.5
- 4.0
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mul { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 10.0
- note: number_div_precision
description: Test Number type division preserves precision
example_rego: "7.5 / 2.5"
literals:
- 7.5
- 2.5
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Div { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 3.0
# Integer Modulo Tests
- note: integer_modulo
description: Test integer modulo works correctly
example_rego: "7 % 3"
literals:
- 7
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Mod { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 1
# Value Ordering Tests
- note: value_ordering_null_bool
description: Test null < bool ordering
example_rego: "null < true"
literals:
- null
- true
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Lt { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: value_ordering_bool_number
description: Test bool < number ordering
example_rego: "true < 1"
literals:
- true
- 1
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Lt { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: value_ordering_number_string
description: Test number < string ordering
example_rego: "1 < \"a\""
literals:
- 1
- "a"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Lt { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
# Edge Cases for Mixed Undefined Operations
- note: undefined_both_operands
description: Test operation with both operands undefined
example_rego: "input.nonexistent1 + input.nonexistent2"
input: {}
literals:
- "nonexistent1"
- "nonexistent2"
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 0, key: 1 }"
- "Index { dest: 4, container: 0, key: 2 }"
- "Add { dest: 5, left: 3, right: 4 }"
- "Return { value: 5 }"
want_result: "#undefined"
- note: undefined_right_operand_arithmetic
description: Test arithmetic with right operand undefined
example_rego: "5 + input.nonexistent"
input: {}
literals:
- 5
- "nonexistent"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadInput { dest: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 1, key: 2 }"
- "Add { dest: 4, left: 0, right: 3 }"
- "Return { value: 4 }"
want_result: "#undefined"
- note: undefined_right_operand_comparison
description: Test comparison with right operand undefined
example_rego: "5 == input.nonexistent"
input: {}
literals:
- 5
- "nonexistent"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadInput { dest: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Index { dest: 3, container: 1, key: 2 }"
- "Eq { dest: 4, left: 0, right: 3 }"
- "Return { value: 4 }"
want_result: "#undefined"

View File

@@ -0,0 +1,61 @@
# Invalid Collection Operations Test Suite
# Exercises error conditions for collection-specific instructions.
cases:
- note: object_set_on_non_object
description: ObjectSet on non-object register triggers error
literals:
- 1
- "key"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "ObjectSet { obj: 0, key: 1, value: 1 }"
want_error: "Register 0 does not contain an object"
- note: array_push_on_non_array
description: ArrayPush on scalar register fails
literals:
- 1
- 2
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 1 }"
want_error: "Register 0 does not contain an array"
- note: set_add_on_non_set
description: SetAdd on scalar register fails
literals:
- 1
- 2
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "SetAdd { set: 0, value: 1 }"
want_error: "Register 0 does not contain a set"
- note: object_create_invalid_template
description: ObjectCreate fails when template literal is not object
literals:
- []
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
want_error: "ObjectCreate: template is not an object"
- note: contains_on_scalar_returns_false
description: Contains on scalar should return false
literals:
- 1
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Contains { dest: 2, collection: 0, value: 1 }"
- "Return { value: 2 }"
want_result: false

View File

@@ -0,0 +1,250 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Load Data and Input Test Suite
# Tests LoadData and LoadInput instructions with various edge cases
# Covers empty, nested, undefined values, and interaction with virtual data lookups
cases:
- note: load_data_empty
description: LoadData from empty data context
example_rego: "data"
data: {}
literals: []
instructions:
- "LoadData { dest: 0 }"
- "Return { value: 0 }"
want_result: {}
- note: load_input_empty
description: LoadInput from empty input context
example_rego: "input"
input: {}
literals: []
instructions:
- "LoadInput { dest: 0 }"
- "Return { value: 0 }"
want_result: {}
- note: load_data_with_values
description: LoadData returns populated data object
example_rego: "data"
data: {}
literals: []
# This would require the test harness to support setting data
# For now, testing structure only
instructions:
- "LoadData { dest: 0 }"
- "Return { value: 0 }"
want_result: {} # Default empty since harness may not set data
- note: load_input_with_values
description: LoadInput returns populated input object
example_rego: "input"
input: {}
literals: []
instructions:
- "LoadInput { dest: 0 }"
- "Return { value: 0 }"
want_result: {} # Default empty
- note: load_data_and_index
description: LoadData followed by indexing
example_rego: "data.users"
data: {}
literals:
- "users"
instructions:
- "LoadData { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined" # users doesn't exist in empty data
- note: load_input_and_index
description: LoadInput followed by indexing
example_rego: "input.user.name"
input: {}
literals:
- "user"
- "name"
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Load { dest: 3, literal_idx: 1 }"
- "Index { dest: 4, container: 2, key: 3 }"
- "Return { value: 4 }"
want_result: "#undefined" # user doesn't exist in empty input
- note: load_data_multiple_times
description: LoadData can be called multiple times
example_rego: "data == data"
data: {}
literals: []
instructions:
- "LoadData { dest: 0 }"
- "LoadData { dest: 1 }"
- "Eq { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: load_input_multiple_times
description: LoadInput can be called multiple times
example_rego: "input == input"
input: {}
literals: []
instructions:
- "LoadInput { dest: 0 }"
- "LoadInput { dest: 1 }"
- "Eq { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: load_data_not_equal_to_input
description: data and input are separate contexts
example_rego: "data == input"
data: {}
input: {}
literals: []
instructions:
- "LoadData { dest: 0 }"
- "LoadInput { dest: 1 }"
- "Eq { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true # Both empty {}
- note: load_data_in_loop
description: LoadData inside loop body
example_rego: "[ data | _ = [1, 2][_] ]"
data: {}
literals:
- 1
- 2
instruction_params:
array_create_params:
- dest: 0
elements: [1, 2]
loop_params:
- mode: ForEach
collection: 0
key_reg: 3
value_reg: 4
result_reg: 7
body_start: 5
loop_end: 8
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayCreate { params_index: 0 }"
- "ArrayNew { dest: 6 }"
- "LoopStart { params_index: 0 }"
# Loop body starts
- "LoadData { dest: 5 }"
- "ArrayPush { arr: 6, value: 5 }"
- "LoopNext { body_start: 5, loop_end: 8 }"
# Loop done
- "Return { value: 6 }"
want_result: [{}, {}]
- note: load_input_in_loop
description: LoadInput inside loop body
example_rego: "[ input | _ = [1, 2][_] ]"
input: {}
literals:
- 1
- 2
instruction_params:
array_create_params:
- dest: 0
elements: [1, 2]
loop_params:
- mode: ForEach
collection: 0
key_reg: 3
value_reg: 4
result_reg: 7
body_start: 5
loop_end: 8
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayCreate { params_index: 0 }"
- "ArrayNew { dest: 6 }"
- "LoopStart { params_index: 0 }"
# Loop body starts
- "LoadInput { dest: 5 }"
- "ArrayPush { arr: 6, value: 5 }"
- "LoopNext { body_start: 5, loop_end: 8 }"
# Loop done
- "Return { value: 6 }"
want_result: [{}, {}]
- note: load_data_in_arithmetic
description: Using LoadData result in arithmetic should fail
example_rego: "data + 1"
data: {}
literals:
- 1
instructions:
- "LoadData { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot add Object({}) and Number(1)"
- note: load_input_in_comparison
description: Compare input to literal object
example_rego: "input == {}"
input: {}
literals:
- {}
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Eq { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: load_data_conditional
description: LoadData in conditional check
example_rego: "data.flag"
data: {}
literals:
- "flag"
instructions:
- "LoadData { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "LoadFalse { dest: 3 }"
- "Or { dest: 4, left: 2, right: 3 }"
- "Return { value: 4 }"
want_result: "#undefined" # flag is undefined
- note: load_data_chained_index
description: Deep path indexing on data
example_rego: "data.a.b.c.d"
data: {}
literals:
- "a"
- "b"
- "c"
- "d"
instruction_params:
chained_index_params:
- dest: 5
root: 0
path_components:
- register: 1
- register: 2
- register: 3
- register: 4
instructions:
- "LoadData { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Load { dest: 4, literal_idx: 3 }"
- "ChainedIndex { params_index: 0 }"
- "Return { value: 5 }"
want_result: "#undefined"

View File

@@ -0,0 +1,43 @@
# Loop Invalid Iteration Test Suite
# Asserts loop error paths and instruction limit behavior.
cases:
- note: loop_start_on_scalar
description: LoopStart over scalar treats collection as empty and leaves result false
literals:
- 1
instruction_params:
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 3
body_start: 2
loop_end: 2
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoopStart { params_index: 0 }"
- "Return { value: 3 }"
want_result: false
- note: instruction_limit_exceeded
description: VM stops once max instruction limit reached
literals:
- [1, 2]
instruction_params:
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 1
value_reg: 2
result_reg: 3
body_start: 2
loop_end: 4
max_instructions: 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoopStart { params_index: 0 }"
- "LoopNext { body_start: 2, loop_end: 4 }"
- "Return { value: 3 }"
want_error: "exceeded maximum instruction limit"

View File

@@ -0,0 +1,160 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Array Comprehension Test Suite
# Tests array comprehensions - collect transformed values based on conditions
# Corresponds to Rego's "[transform | condition]" patterns
cases:
- note: array_simple_transform
description: Simple array comprehension with transformation
example_rego: |
# Transform array elements by doubling them
[x * 2 | x := [1, 2, 3][_]] # [2, 4, 6]
literals:
- 1
- 2
- 3
- 2 # multiplier
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 7
key_reg: 4
value_reg: 5
body_start: 8
comprehension_end: 11
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 8
body_start: 9
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Create input array [1, 2, 3] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "ArrayPush { arr: 0, value: 2 }" # Push 2 to array
- "Load { dest: 3, literal_idx: 2 }" # Load 3 into register 3
- "ArrayPush { arr: 0, value: 3 }" # Push 3 to array
- "ComprehensionBegin { params_index: 0 }" # Start array comprehension and initialize result in register 7
- "LoopStart { params_index: 0 }" # Start loop over array elements
- "Load { dest: 6, literal_idx: 3 }" # Load multiplier 2 into register 6
- "Mul { dest: 9, left: 5, right: 6 }" # Multiply current value by 2, store result in register 9
- "ComprehensionYield { value_reg: 9 }" # Add transformed value to comprehension
- "LoopNext { body_start: 9, loop_end: 12 }" # Continue to next iteration or exit
- "Return { value: 7 }" # Return comprehension collection
want_result: [2, 4, 6]
- note: array_empty_input
description: Array comprehension with empty input
example_rego: |
# Transform empty array
[x + 5 | x := [][_]] # [] (empty array)
literals:
- 5 # addend
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 7
key_reg: 4
value_reg: 5
body_start: 2
comprehension_end: 6
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 8
body_start: 3
loop_end: 6
instructions:
- "ArrayNew { dest: 0 }" # Create empty input array in register 0
- "ComprehensionBegin { params_index: 0 }" # Start array comprehension and initialize result in register 7
- "LoopStart { params_index: 0 }" # Start loop over array elements
- "Load { dest: 6, literal_idx: 0 }" # Load addend 5 into register 6
- "Add { dest: 8, left: 5, right: 6 }" # Add 5 to current value, store result in register 8
- "ComprehensionYield { value_reg: 8 }" # Add transformed value to comprehension
- "LoopNext { body_start: 3, loop_end: 6 }" # Continue to next iteration or exit
- "Return { value: 7 }" # Return comprehension collection
want_result: []
- note: array_single_element
description: Array comprehension with single element
example_rego: |
# Transform single element array
[x - 1 | x := [10][_]] # [9]
literals:
- 10
- 1 # subtrahend
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 7
key_reg: 4
value_reg: 5
body_start: 4
comprehension_end: 8
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 8
body_start: 5
loop_end: 8
instructions:
- "ArrayNew { dest: 0 }" # Create input array [10] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 10 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 10 to array
- "ComprehensionBegin { params_index: 0 }" # Start array comprehension and initialize result in register 7
- "LoopStart { params_index: 0 }" # Start loop over array elements
- "Load { dest: 6, literal_idx: 1 }" # Load subtrahend 1 into register 6
- "Sub { dest: 9, left: 5, right: 6 }" # Subtract 1 from current value, store result in register 9
- "ComprehensionYield { value_reg: 9 }" # Add transformed value to comprehension
- "LoopNext { body_start: 5, loop_end: 8 }" # Continue to next iteration or exit
- "Return { value: 7 }" # Return comprehension collection
want_result: [9]
- note: array_with_null_values
description: Array comprehension with null value handling
example_rego: |
# Process array with null values - nulls are preserved
[x | x := [1, null, 3][_]] # [1, null, 3]
literals:
- 1
- 3
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 7
key_reg: 4
value_reg: 5
body_start: 8
comprehension_end: 11
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 8
body_start: 9
loop_end: 11
instructions:
- "ArrayNew { dest: 0 }" # Create input array in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "LoadNull { dest: 2 }" # Load null value
- "ArrayPush { arr: 0, value: 2 }" # Push null to array
- "Load { dest: 3, literal_idx: 1 }" # Load 3
- "ArrayPush { arr: 0, value: 3 }" # Push 3 to array
- "ComprehensionBegin { params_index: 0 }" # Start array comprehension and initialize result in register 7
- "LoopStart { params_index: 0 }" # Start loop over array elements
- "ComprehensionYield { value_reg: 5 }" # Add current value (including null) to comprehension
- "LoopNext { body_start: 9, loop_end: 11 }" # Continue to next iteration or exit
- "Return { value: 7 }" # Return comprehension collection
want_result: [1, null, 3]

View File

@@ -0,0 +1,295 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Empty Collections Loop Test Suite
# Tests behavior of various loop types over empty collections
# 1. Comprehensions should evaluate to their empty versions
# 2. some..in should evaluate to false
# 3. every should evaluate to true
cases:
- note: existential_empty_array
description: Existential quantification (some) on empty array should return false
example_rego: |
# some x in []
# x > 0 # false - no elements to satisfy condition
literals:
- {}
- 0 # comparison value
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 4
value_reg: 5
body_start: 2
loop_end: 6
result_reg: 6
instructions:
- "ArrayNew { dest: 0 }" # Create empty array in register 0
- "LoopStart { params_index: 0 }"
- "Load { dest: 7, literal_idx: 1 }" # Load comparison value 0
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 0
- "AssertCondition { condition: 8 }" # Assert the condition
- "LoopNext { body_start: 2, loop_end: 6 }"
- "Return { value: 6 }" # Return false for empty collection
want_result: false
- note: universal_empty_array
description: Universal quantification (every) on empty array should return true
example_rego: |
# every x in []
# x > 0 # true - vacuously true (no elements to violate condition)
literals:
- {}
- 0 # comparison value
instruction_params:
loop_params:
- mode: "Every"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 2
loop_end: 6
instructions:
- "ArrayNew { dest: 0 }" # Create empty array in register 0
- "LoopStart { params_index: 0 }"
- "Load { dest: 7, literal_idx: 1 }" # Load comparison value 0
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 0
- "AssertCondition { condition: 8 }" # Assert the condition
- "LoopNext { body_start: 2, loop_end: 6 }"
- "Return { value: 6 }" # Return true for empty collection (vacuously true)
want_result: true
- note: array_comprehension_empty
description: Array comprehension on empty collection should return empty array
example_rego: |
# [x + 1 | x = []; true] # []
# Transform each element by adding 1
literals:
- {}
- 1 # value to add
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 1
key_reg: 4
value_reg: 5
body_start: 3
comprehension_end: 9
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 8
body_start: 4
loop_end: 9
instructions:
- "ArrayNew { dest: 0 }" # Create empty input array in register 0
- "ComprehensionBegin { params_index: 0 }" # Start array comprehension
- "LoopStart { params_index: 0 }" # Start loop over array elements
- "Load { dest: 6, literal_idx: 1 }" # Load 1 into register 6
- "Add { dest: 7, left: 5, right: 6 }" # Add 1 to current value
- "ComprehensionYield { value_reg: 7 }" # Add result to comprehension
- "LoadBool { dest: 8, value: true }" # Load true (condition always passes)
- "AssertCondition { condition: 8 }" # Assert true condition
- "LoopNext { body_start: 4, loop_end: 9 }" # Continue to next iteration or exit
- "Return { value: 1 }" # Return the result array (should be empty)
want_result: []
- note: set_comprehension_empty
description: Set comprehension on empty collection should return empty set
example_rego: |
# {x + 1 | x = []; true} # set()
# Transform each element by adding 1 into a set
literals:
- {}
- 1 # value to add
instruction_params:
comprehension_begin_params:
- mode: "Set"
collection_reg: 1
key_reg: 4
value_reg: 5
body_start: 3
comprehension_end: 9
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 8
body_start: 4
loop_end: 9
instructions:
- "ArrayNew { dest: 0 }" # Create empty input array in register 0
- "ComprehensionBegin { params_index: 0 }" # Start set comprehension
- "LoopStart { params_index: 0 }" # Start loop over array elements
- "Load { dest: 6, literal_idx: 1 }" # Load 1 into register 6
- "Add { dest: 7, left: 5, right: 6 }" # Add 1 to current value
- "ComprehensionYield { value_reg: 7 }" # Add result to comprehension
- "LoadBool { dest: 8, value: true }" # Load true (condition always passes)
- "AssertCondition { condition: 8 }" # Assert true condition
- "LoopNext { body_start: 4, loop_end: 9 }" # Continue to next iteration or exit
- "Return { value: 1 }" # Return the result set (should be empty)
want_result:
set!: [] # Set serializes as empty array
- note: object_comprehension_empty
description: Object comprehension on empty collection should return empty object
example_rego: |
# {k: v + 1 | some k, v in {}; true} # {}
# Transform each key-value pair
literals:
- {}
- 1 # value to add
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
comprehension_begin_params:
- mode: "Object"
collection_reg: 1
key_reg: 4
value_reg: 5
body_start: 3
comprehension_end: 9
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 8
body_start: 4
loop_end: 9
instructions:
- "ObjectCreate { params_index: 0 }"
- "ComprehensionBegin { params_index: 0 }" # Start object comprehension
- "LoopStart { params_index: 0 }" # Start loop over object elements
- "Load { dest: 6, literal_idx: 1 }" # Load 1 into register 6
- "Add { dest: 7, left: 5, right: 6 }" # Add 1 to current value
- "ComprehensionYield { value_reg: 7 }" # Add result to comprehension (object comprehension needs special handling)
- "LoadBool { dest: 8, value: true }" # Load true (condition always passes)
- "AssertCondition { condition: 8 }" # Assert true condition
- "LoopNext { body_start: 4, loop_end: 9 }" # Continue to next iteration or exit
- "Return { value: 1 }" # Return the result object (should be empty)
want_result: {}
- note: existential_empty_set
description: Existential quantification on empty set should return false
example_rego: |
# some x in set()
# x > 0 # false - no elements in set
literals:
- {}
- 0 # comparison value
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 2
loop_end: 6
instructions:
- "SetNew { dest: 0 }" # Create empty set in register 0
- "LoopStart { params_index: 0 }"
- "Load { dest: 7, literal_idx: 1 }" # Load comparison value 0
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 0
- "AssertCondition { condition: 8 }" # Assert the condition
- "LoopNext { body_start: 2, loop_end: 6 }"
- "Return { value: 6 }" # Return false for empty set
want_result: false
- note: universal_empty_object
description: Universal quantification on empty object should return true
example_rego: |
# every k, v in {}
# v > 0 # true - vacuously true (no key-value pairs to violate condition)
literals:
- {}
- 0 # comparison value
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
loop_params:
- mode: "Every"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 2
loop_end: 6
instructions:
- "ObjectCreate { params_index: 0 }"
- "LoopStart { params_index: 0 }"
- "Load { dest: 7, literal_idx: 1 }" # Load comparison value 0
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 0
- "AssertCondition { condition: 8 }" # Assert the condition
- "LoopNext { body_start: 2, loop_end: 6 }"
- "Return { value: 6 }" # Return true for empty object (vacuously true)
want_result: true
- note: nested_empty_comprehensions
description: Nested comprehensions with empty collections
example_rego: |
# [[y | y = []; true] | x = []; true] # []
# Nested array comprehension where both inner and outer collections are empty
literals: []
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 0
key_reg: 2
value_reg: 3
body_start: 3
comprehension_end: 16
- mode: "Array"
collection_reg: 6
key_reg: 8
value_reg: 9
body_start: 7
comprehension_end: 12
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 2
value_reg: 3
result_reg: 10
body_start: 4
loop_end: 16
- mode: "ForEach"
collection: 6
key_reg: 8
value_reg: 9
result_reg: 11
body_start: 8
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Create empty outer array in register 0
- "ArrayNew { dest: 1 }" # Create empty result array in register 1
- "ComprehensionBegin { params_index: 0 }"
- "LoopStart { params_index: 0 }" # Start outer loop
# Inner array comprehension (for each x in outer empty array)
- "ArrayNew { dest: 6 }" # Create empty inner array in register 6
- "ArrayNew { dest: 7 }" # Create result for inner comprehension in register 7
- "ComprehensionBegin { params_index: 1 }"
- "LoopStart { params_index: 1 }" # Start inner loop
- "ComprehensionYield { value_reg: 9 }" # Push inner value to inner result (never executes)
- "LoadBool { dest: 10, value: true }" # Load true
- "AssertCondition { condition: 10 }" # Assert true condition for inner loop
- "LoopNext { body_start: 8, loop_end: 12 }" # Continue inner loop
- "ComprehensionYield { value_reg: 7 }" # Push inner result to outer result
- "LoadBool { dest: 11, value: true }" # Load true
- "AssertCondition { condition: 11 }" # Assert true condition for outer loop
- "LoopNext { body_start: 4, loop_end: 16 }" # Continue outer loop
- "Return { value: 1 }" # Return the nested result (should be empty)
want_result: []

View File

@@ -0,0 +1,174 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Existential Loops Test Suite (some)
# Tests existential quantification loops - succeed if ANY element satisfies the condition
# Corresponds to Rego's "some x in collection; condition" patterns
cases:
- note: existential_basic_some
description: Basic existential quantification - some element satisfies condition
example_rego: |
# Check if any element in array is greater than 2
some x in [1, 2, 3]
x > 2 # true (3 > 2)
literals:
- 1
- 2
- 3
- 2 # comparison value
instruction_params:
loop_params:
- mode: "Existential"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 8
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Create input array [1, 2, 3] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "ArrayPush { arr: 0, value: 2 }" # Push 2 to array
- "Load { dest: 3, literal_idx: 2 }" # Load 3 into register 3
- "ArrayPush { arr: 0, value: 3 }" # Push 3 to array
- "LoopStart { params_index: 0 }" # Start existential loop using parameter table index 0
- "Load { dest: 7, literal_idx: 3 }" # Load comparison value 2 into register 7
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 2
- "AssertCondition { condition: 8 }" # Assert the condition result for existential logic
- "LoopNext { body_start: 8, loop_end: 12 }" # Continue to next iteration or exit early if condition met
- "Return { value: 6 }" # Return result (true if any element satisfied condition)
want_result: true
- note: existential_none_satisfy
description: Existential quantification where no element satisfies condition
example_rego: |
# Check if any element in array is greater than 5
some x in [1, 2]
x > 5 # false (no element > 5)
literals:
- 1
- 2
- 5 # comparison value
instruction_params:
loop_params:
- mode: "Existential"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 6
loop_end: 10
instructions:
- "ArrayNew { dest: 0 }" # Create input array [1, 2] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "ArrayPush { arr: 0, value: 2 }" # Push 2 to array
- "LoopStart { params_index: 0 }" # Start existential loop using parameter table index 0
- "Load { dest: 7, literal_idx: 2 }" # Load comparison value 5 into register 7
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 5
- "AssertCondition { condition: 8 }" # Assert the condition result for existential logic
- "LoopNext { body_start: 6, loop_end: 10 }" # Continue to next iteration
- "Return { value: 6 }" # Return result (false since no element satisfied condition)
want_result: false
- note: existential_empty_collection
description: Existential quantification on empty collection
example_rego: |
# Check if any element in empty array satisfies condition
some x in []
x > 0 # false (no elements to check)
literals:
- 0 # comparison value
instruction_params:
loop_params:
- mode: "Existential"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 2
loop_end: 6
instructions:
- "ArrayNew { dest: 0 }" # Create empty input array in register 0
- "LoopStart { params_index: 0 }" # Start existential loop using parameter table index 0
- "Load { dest: 7, literal_idx: 0 }" # Load comparison value 0 into register 7
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 0
- "AssertCondition { condition: 8 }" # Assert the condition result for existential logic
- "LoopNext { body_start: 2, loop_end: 6 }" # Continue to next iteration
- "Return { value: 6 }" # Return result (false for empty collection)
want_result: false
- note: existential_simplified_arrays
description: Existential quantification with simple array test
example_rego: |
# Check if any element in array is greater than 5
# Simplified version: check if [3, 7, 4] contains element > 5
some x in [3, 7, 4]
x > 5 # true (7 > 5)
literals:
- 3
- 7
- 4
- 5 # comparison value
instruction_params:
loop_params:
- mode: "Existential"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 8
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Create array [3, 7, 4] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 3
- "ArrayPush { arr: 0, value: 1 }" # Push 3 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 7
- "ArrayPush { arr: 0, value: 2 }" # Push 7 to array
- "Load { dest: 3, literal_idx: 2 }" # Load 4
- "ArrayPush { arr: 0, value: 3 }" # Push 4 to array
- "LoopStart { params_index: 0 }" # Start existential loop using parameter table index 0
- "Load { dest: 7, literal_idx: 3 }" # Load comparison value 5
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 5
- "AssertCondition { condition: 8 }" # Assert the condition for existential logic
- "LoopNext { body_start: 8, loop_end: 12 }" # Continue to next iteration
- "Return { value: 6 }" # Return result
want_result: true
- note: some_basic_failure
description: Basic existential loop that fails
example_rego: "some x in [1, 2, 3]; x > 5" # false because no element > 5
literals:
- 1
- 2
- 3
- 5 # comparison value
instruction_params:
loop_params:
- mode: "Existential"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 8
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Create array [1, 2, 3] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "ArrayPush { arr: 0, value: 2 }" # Push 2 to array
- "Load { dest: 3, literal_idx: 2 }" # Load 3 into register 3
- "ArrayPush { arr: 0, value: 3 }" # Push 3 to array
- "LoopStart { params_index: 0 }" # Start existential loop using parameter table index 0
- "Load { dest: 7, literal_idx: 3 }" # Load comparison value 5 into register 7
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 5, store result in register 8
- "AssertCondition { condition: 8 }" # Assert the condition (fails for all elements)
- "LoopNext { body_start: 8, loop_end: 12 }" # Continue to next iteration or exit
- "Return { value: 6 }" # Return boolean result from loop
want_result: false

View File

@@ -0,0 +1,223 @@
# Advanced Loop and Comprehension Interaction Suite
# Exercises nested quantifiers inside comprehensions and object key/value emission.
cases:
- note: array_comprehension_filters_with_inner_any
description: Array comprehension keeps only members whose nested array passes an Any loop
example_rego: |
[arr |
arr := [[1, 0], [1, 2]][_];
some v in arr; v == 0
]
literals:
- 1
- 0
- 2
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 7
result_reg: 7
key_reg: 10
value_reg: 11
body_start: 14
comprehension_end: 23
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 15
loop_end: 23
- mode: "Any"
collection: 11
key_reg: 13
value_reg: 14
result_reg: 15
body_start: 16
loop_end: 21
instructions:
- "ArrayNew { dest: 0 }"
- "ArrayNew { dest: 1 }"
- "Load { dest: 2, literal_idx: 0 }"
- "ArrayPush { arr: 1, value: 2 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ArrayPush { arr: 1, value: 3 }"
- "ArrayPush { arr: 0, value: 1 }"
- "ArrayNew { dest: 4 }"
- "Load { dest: 5, literal_idx: 0 }"
- "ArrayPush { arr: 4, value: 5 }"
- "Load { dest: 6, literal_idx: 2 }"
- "ArrayPush { arr: 4, value: 6 }"
- "ArrayPush { arr: 0, value: 4 }"
- "ComprehensionBegin { params_index: 0 }"
- "LoopStart { params_index: 0 }"
- "LoopStart { params_index: 1 }"
- "Load { dest: 16, literal_idx: 1 }"
- "Eq { dest: 17, left: 14, right: 16 }"
- "AssertCondition { condition: 17 }"
- "ComprehensionYield { value_reg: 11 }"
- "LoopNext { body_start: 16, loop_end: 21 }"
- "LoopNext { body_start: 15, loop_end: 23 }"
- "ComprehensionEnd"
- "Return { value: 7 }"
want_result:
- [1, 0]
- note: array_comprehension_requires_inner_every
description: Array comprehension keeps only members whose nested array passes an Every loop
example_rego: |
[arr |
arr := [[1, 1], [-1, 2], [2, 3]][_];
every v in arr; v > 0
]
literals:
- 1
- -1
- 2
- 3
- 0
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 9
result_reg: 9
key_reg: 10
value_reg: 11
body_start: 20
comprehension_end: 29
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 20
loop_end: 29
- mode: "ForEach"
collection: 11
key_reg: 13
value_reg: 14
result_reg: 18
body_start: 22
loop_end: 26
instructions:
- "ArrayNew { dest: 0 }"
- "ArrayNew { dest: 1 }"
- "Load { dest: 2, literal_idx: 0 }"
- "ArrayPush { arr: 1, value: 2 }"
- "ArrayPush { arr: 1, value: 2 }"
- "ArrayPush { arr: 0, value: 1 }"
- "ArrayNew { dest: 3 }"
- "Load { dest: 4, literal_idx: 1 }"
- "ArrayPush { arr: 3, value: 4 }"
- "Load { dest: 5, literal_idx: 2 }"
- "ArrayPush { arr: 3, value: 5 }"
- "ArrayPush { arr: 0, value: 3 }"
- "ArrayNew { dest: 6 }"
- "Load { dest: 7, literal_idx: 2 }"
- "ArrayPush { arr: 6, value: 7 }"
- "Load { dest: 8, literal_idx: 3 }"
- "ArrayPush { arr: 6, value: 8 }"
- "ArrayPush { arr: 0, value: 6 }"
- "ComprehensionBegin { params_index: 0 }"
- "LoopStart { params_index: 0 }"
- "LoadTrue { dest: 15 }"
- "LoopStart { params_index: 1 }"
- "Load { dest: 16, literal_idx: 4 }"
- "Gt { dest: 17, left: 14, right: 16 }"
- "And { dest: 15, left: 15, right: 17 }"
- "LoopNext { body_start: 22, loop_end: 26 }"
- "AssertCondition { condition: 15 }"
- "ComprehensionYield { value_reg: 11 }"
- "LoopNext { body_start: 20, loop_end: 29 }"
- "ComprehensionEnd"
- "Return { value: 9 }"
want_result:
- [1, 1]
- [2, 3]
- note: object_comprehension_with_nested_any
description: Object comprehension emits keys only when nested Any loop succeeds
example_rego: |
{ entry[0]: true |
entry := [["a", [1, 2]], ["b", [1]]][_];
some v in entry[1]; v % 2 == 0
}
literals:
- {}
- "a"
- 1
- 2
- "b"
- 0
instruction_params:
object_create_params:
- dest: 12
template_literal_idx: 0
literal_key_fields: []
fields: []
comprehension_begin_params:
- mode: "Object"
collection_reg: 12
result_reg: 12
key_reg: 17
value_reg: 22
body_start: 21
comprehension_end: 36
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 13
value_reg: 14
result_reg: 15
body_start: 22
loop_end: 36
- mode: "Any"
collection: 19
key_reg: 20
value_reg: 21
result_reg: 22
body_start: 27
loop_end: 33
instructions:
- "ArrayNew { dest: 0 }"
- "ArrayNew { dest: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 1, value: 2 }"
- "ArrayNew { dest: 3 }"
- "Load { dest: 4, literal_idx: 2 }"
- "ArrayPush { arr: 3, value: 4 }"
- "Load { dest: 5, literal_idx: 3 }"
- "ArrayPush { arr: 3, value: 5 }"
- "ArrayPush { arr: 1, value: 3 }"
- "ArrayPush { arr: 0, value: 1 }"
- "ArrayNew { dest: 6 }"
- "Load { dest: 7, literal_idx: 4 }"
- "ArrayPush { arr: 6, value: 7 }"
- "ArrayNew { dest: 8 }"
- "Load { dest: 9, literal_idx: 2 }"
- "ArrayPush { arr: 8, value: 9 }"
- "ArrayPush { arr: 6, value: 8 }"
- "ArrayPush { arr: 0, value: 6 }"
- "ObjectCreate { params_index: 0 }"
- "ComprehensionBegin { params_index: 0 }"
- "LoopStart { params_index: 0 }"
- "Load { dest: 16, literal_idx: 5 }"
- "Index { dest: 17, container: 14, key: 16 }"
- "Load { dest: 18, literal_idx: 2 }"
- "Index { dest: 19, container: 14, key: 18 }"
- "LoopStart { params_index: 1 }"
- "Load { dest: 23, literal_idx: 3 }"
- "Mod { dest: 24, left: 21, right: 23 }"
- "Load { dest: 25, literal_idx: 5 }"
- "Eq { dest: 26, left: 24, right: 25 }"
- "AssertCondition { condition: 26 }"
- "LoopNext { body_start: 27, loop_end: 33 }"
- "AssertCondition { condition: 22 }"
- "ComprehensionYield { value_reg: 22, key_reg: 17 }"
- "LoopNext { body_start: 22, loop_end: 36 }"
- "ComprehensionEnd"
- "Return { value: 12 }"
want_result: {"a": true}

View File

@@ -0,0 +1,183 @@
name: "Nested Loops Test Suite"
description: "Test various combinations and levels of nesting for different looping constructs"
cases:
- note: "simple_nested_comprehension"
description: "Test simple nested array comprehension"
example_rego: |
[[x | x := [1, 2][_]] | _ := [1, 2][_]]
literals:
- 1
- 2
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 1
key_reg: 2
value_reg: 3
body_start: 6
comprehension_end: 23
- mode: "Array"
collection_reg: 11
key_reg: 12
value_reg: 13
body_start: 12
comprehension_end: 20
loop_params:
- mode: "ForEach"
collection: 6
key_reg: 7
value_reg: 8
result_reg: 9
body_start: 7
loop_end: 22
- mode: "ForEach"
collection: 16
key_reg: 17
value_reg: 18
result_reg: 19
body_start: 15
loop_end: 18
instructions:
- "ComprehensionBegin { params_index: 0 }" # array comprehension in r1, body: 4-21 (P0)
- "Load { dest: 4, literal_idx: 0 }" # Load literal: 1
- "Load { dest: 5, literal_idx: 1 }" # Load literal: 2
- "ArrayNew { dest: 6 }" # Create empty array r6
- "ArrayPush { arr: 6, value: 4 }" # Push r4 to r6
- "ArrayPush { arr: 6, value: 5 }" # Push r5 to r6 -> [1, 2]
- "LoopStart { params_index: 0 }" # foreach loop over r6, body: 8-20 (P0)
# Outer loop body starts here (index 7)
- "Move { dest: 10, src: 8 }" # Copy value from r8 to r10
- "ComprehensionBegin { params_index: 1 }" # array comprehension in r11, body: 10-18 (P1)
- "Load { dest: 14, literal_idx: 0 }" # Load literal: 1
- "Load { dest: 15, literal_idx: 1 }" # Load literal: 2
- "ArrayNew { dest: 16 }" # Create empty array r16
- "ArrayPush { arr: 16, value: 14 }" # Push r14 to r16
- "ArrayPush { arr: 16, value: 15 }" # Push r15 to r16 -> [1, 2]
- "LoopStart { params_index: 1 }" # foreach loop over r16, body: 14-17 (P1)
# Inner loop body starts here (index 16)
- "Move { dest: 20, src: 18 }" # Copy value from r18 to r20
- "ComprehensionYield { value_reg: 20 }" # Yield value to comprehension
- "LoopNext { body_start: 16, loop_end: 19 }" # continue → 16 or exit → 19
# Inner comprehension end (index 19)
- "ComprehensionEnd" # End comprehension block
- "ComprehensionYield { value_reg: 11 }" # Yield value to comprehension
- "LoopNext { body_start: 7, loop_end: 22 }" # continue → 7 or exit → 22
# Outer comprehension end (index 22)
- "ComprehensionEnd" # End comprehension block
- "Move { dest: 0, src: 1 }" # Copy value from r1 to r0
- "Return { value: 0 }" # Return value from r0
want_result: [[1, 2], [1, 2]]
- note: "some_nested_comprehension"
description: "Test some with nested array comprehension"
example_rego: |
[1, 2][_] == [x | x := [1, 2, 3][_]; x > 1][_]
literals:
- 1
- 2
- 3
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 12
result_reg: 12
key_reg: 10
value_reg: 11
body_start: 16
comprehension_end: 20
loop_params:
- mode: "Any"
collection: 0
key_reg: 7
value_reg: 8
result_reg: 9
body_start: 14
loop_end: 27
- mode: "ForEach"
collection: 3
key_reg: 10
value_reg: 11
result_reg: 21
body_start: 16
loop_end: 20
- mode: "Any"
collection: 12
key_reg: 13
value_reg: 14
result_reg: 15
body_start: 22
loop_end: 25
instructions:
- "ArrayNew { dest: 0 }" # Index 0: Build left array [1, 2]
- "Load { dest: 1, literal_idx: 0 }" # Index 1: Load literal 1
- "ArrayPush { arr: 0, value: 1 }" # Index 2
- "Load { dest: 2, literal_idx: 1 }" # Index 3: Load literal 2
- "ArrayPush { arr: 0, value: 2 }" # Index 4
- "ArrayNew { dest: 3 }" # Index 5: Build source array [1, 2, 3]
- "Load { dest: 4, literal_idx: 0 }" # Index 6
- "ArrayPush { arr: 3, value: 4 }" # Index 7
- "Load { dest: 5, literal_idx: 1 }" # Index 8
- "ArrayPush { arr: 3, value: 5 }" # Index 9
- "Load { dest: 6, literal_idx: 2 }" # Index 10
- "ArrayPush { arr: 3, value: 6 }" # Index 11
- "Load { dest: 16, literal_idx: 0 }" # Index 12: Load 1 for comparison (stays stable)
- "LoopStart { params_index: 0 }" # Index 13: Start outer some loop over [1, 2]
- "ComprehensionBegin { params_index: 0 }" # Index 14: Build filtered comprehension
- "LoopStart { params_index: 1 }" # Index 15: Iterate source values for comprehension
- "Gt { dest: 17, left: 11, right: 16 }" # Index 16: Check x > 1
- "AssertCondition { condition: 17 }" # Index 17: Skip values <= 1
- "ComprehensionYield { value_reg: 11 }" # Index 18: Include qualifying value
- "LoopNext { body_start: 16, loop_end: 20 }" # Index 19: Continue comprehension loop
- "ComprehensionEnd" # Index 20: Finish comprehension block
- "LoopStart { params_index: 2 }" # Index 21: Iterate comprehension results
- "Eq { dest: 18, left: 8, right: 14 }" # Index 22: Compare outer value with result value
- "AssertCondition { condition: 18 }" # Index 23: Success when values match
- "LoopNext { body_start: 22, loop_end: 25 }" # Index 24: Continue inner any loop
- "AssertCondition { condition: 15 }" # Index 25: Require some match from inner any loop
- "LoopNext { body_start: 14, loop_end: 27 }" # Index 26: Continue outer some loop
- "Return { value: 9 }" # Index 27
want_result: true
- note: "nested_with_condition"
description: "Test nested loops with conditional logic"
example_rego: |
[x | x := [1, 2, 3][_]; x > 1]
literals:
- 1
- 2
- 3
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 6
result_reg: 6
key_reg: 4
value_reg: 5
body_start: 9
comprehension_end: 14
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 7
body_start: 9
loop_end: 14
instructions:
- "ArrayNew { dest: 0 }" # Index 0: Create input array [1, 2, 3]
- "Load { dest: 1, literal_idx: 0 }" # Index 1: Load 1
- "ArrayPush { arr: 0, value: 1 }" # Index 2: Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Index 3: Load 2
- "ArrayPush { arr: 0, value: 2 }" # Index 4: Push 2 to array
- "Load { dest: 3, literal_idx: 2 }" # Index 5: Load 3
- "ArrayPush { arr: 0, value: 3 }" # Index 6: Push 3 to array
- "ComprehensionBegin { params_index: 0 }" # Index 7: Start comprehension
- "LoopStart { params_index: 0 }" # Index 8: Start loop
- "Load { dest: 7, literal_idx: 0 }" # Index 9: Load 1 for comparison
- "Gt { dest: 8, left: 5, right: 7 }" # Index 10: x > 1
- "AssertCondition { condition: 8 }" # Index 11: Assert x > 1 (skip if false)
- "ComprehensionYield { value_reg: 5 }" # Index 12: Push x to result if condition true
- "LoopNext { body_start: 9, loop_end: 13 }" # Index 13: Continue loop
- "Return { value: 6 }" # Index 14: Return comprehension result
want_result: [2, 3]

View File

@@ -0,0 +1,7 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Placeholder for nested fixed loops - currently empty
# TODO: Add test cases for fixed nested loop scenarios
cases: []

View File

@@ -0,0 +1,192 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Object Comprehension Test Suite
# Tests object comprehensions - construct objects with key-value pairs based on conditions
# Corresponds to Rego's "{key: value | condition}" patterns
cases:
- note: object_simple_key_value
description: Simple object comprehension with computed values
example_rego: |
# Create object mapping each value to its double
{x: x * 2 | x := [1, 2, 3][_]} # {1: 2, 2: 4, 3: 6}
literals:
- {}
- 1
- 2
- 3
- 2 # multiplier
instruction_params:
object_create_params:
- dest: 9
template_literal_idx: 0
literal_key_fields: []
fields: []
comprehension_begin_params:
- mode: "Object"
collection_reg: 9
result_reg: 9
key_reg: 4
value_reg: 5
body_start: 10
comprehension_end: 13
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 10
body_start: 10
loop_end: 14
instructions:
- "ArrayNew { dest: 0 }" # Index 0: Create input array [1, 2, 3]
- "Load { dest: 1, literal_idx: 1 }" # Index 1: Load 1
- "ArrayPush { arr: 0, value: 1 }" # Index 2
- "Load { dest: 2, literal_idx: 2 }" # Index 3: Load 2
- "ArrayPush { arr: 0, value: 2 }" # Index 4
- "Load { dest: 3, literal_idx: 3 }" # Index 5: Load 3
- "ArrayPush { arr: 0, value: 3 }" # Index 6
- "ObjectCreate { params_index: 0 }" # Index 7: Create empty result object in r9
- "ComprehensionBegin { params_index: 0 }" # Index 8: Start object comprehension
- "LoopStart { params_index: 0 }" # Index 9: Start loop
- "Load { dest: 11, literal_idx: 4 }" # Index 10: Load multiplier 2
- "Mul { dest: 12, left: 5, right: 11 }" # Index 11: Multiply value by 2
- "ComprehensionYield { value_reg: 12, key_reg: 5 }" # Index 12: Add key-value pair
- "LoopNext { body_start: 10, loop_end: 14 }" # Index 13: Continue loop
- "Return { value: 9 }" # Index 14: Return result object
want_result: {1: 2, 2: 4, 3: 6}
- note: object_empty_input
description: Object comprehension with empty input
example_rego: |
# Create object from empty array
{x: x + 5 | x := [][_]} # {} (empty object)
literals:
- {}
- 5 # addend
instruction_params:
object_create_params:
- dest: 9
template_literal_idx: 0
literal_key_fields: []
fields: []
comprehension_begin_params:
- mode: "Object"
collection_reg: 9
result_reg: 9
key_reg: 4
value_reg: 5
body_start: 4
comprehension_end: 7
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 10
body_start: 4
loop_end: 8
instructions:
- "ArrayNew { dest: 0 }" # Index 0: Create empty input array
- "ObjectCreate { params_index: 0 }" # Index 1: Create empty result object in r9
- "ComprehensionBegin { params_index: 0 }" # Index 2: Start object comprehension
- "LoopStart { params_index: 0 }" # Index 3: Start loop
- "Load { dest: 10, literal_idx: 1 }" # Index 4: Load addend 5
- "Add { dest: 11, left: 5, right: 10 }" # Index 5: Add 5 to value
- "ComprehensionYield { value_reg: 11, key_reg: 5 }" # Index 6: Add key-value pair
- "LoopNext { body_start: 4, loop_end: 8 }" # Index 7: Continue loop
- "Return { value: 9 }" # Index 8: Return result object
want_result: {}
- note: object_single_element
description: Object comprehension with single element
example_rego: |
# Create object with single key-value pair
{x: x - 1 | x := [5][_]} # {5: 4}
literals:
- {}
- 5
- 1 # subtrahend
instruction_params:
object_create_params:
- dest: 9
template_literal_idx: 0
literal_key_fields: []
fields: []
comprehension_begin_params:
- mode: "Object"
collection_reg: 9
result_reg: 9
key_reg: 4
value_reg: 5
body_start: 6
comprehension_end: 9
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 10
body_start: 6
loop_end: 10
instructions:
- "ArrayNew { dest: 0 }" # Index 0: Create input array [5]
- "Load { dest: 1, literal_idx: 1 }" # Index 1: Load 5
- "ArrayPush { arr: 0, value: 1 }" # Index 2: Push 5 to array
- "ObjectCreate { params_index: 0 }" # Index 3: Create empty result object in r9
- "ComprehensionBegin { params_index: 0 }" # Index 4: Start object comprehension
- "LoopStart { params_index: 0 }" # Index 5: Start loop
- "Load { dest: 10, literal_idx: 2 }" # Index 6: Load subtrahend 1
- "Sub { dest: 11, left: 5, right: 10 }" # Index 7: Subtract 1 from value
- "ComprehensionYield { value_reg: 11, key_reg: 5 }" # Index 8: Add key-value pair
- "LoopNext { body_start: 6, loop_end: 10 }" # Index 9: Continue loop
- "Return { value: 9 }" # Index 10: Return result object
want_result: {5: 4}
- note: object_with_null_keys
description: Object comprehension with null keys and values
example_rego: |
# Create object with null keys/values
{x: x | x := [1, null, 2][_]} # {1: 1, null: null, 2: 2}
literals:
- {}
- 1
- 2
instruction_params:
object_create_params:
- dest: 9
template_literal_idx: 0
literal_key_fields: []
fields: []
comprehension_begin_params:
- mode: "Object"
collection_reg: 9
result_reg: 9
key_reg: 4
value_reg: 5
body_start: 10
comprehension_end: 11
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 10
body_start: 10
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Index 0: Create input array
- "Load { dest: 1, literal_idx: 1 }" # Index 1: Load 1
- "ArrayPush { arr: 0, value: 1 }" # Index 2: Push 1 to array
- "LoadNull { dest: 2 }" # Index 3: Load null value
- "ArrayPush { arr: 0, value: 2 }" # Index 4: Push null to array
- "Load { dest: 3, literal_idx: 2 }" # Index 5: Load 2
- "ArrayPush { arr: 0, value: 3 }" # Index 6: Push 2 to array
- "ObjectCreate { params_index: 0 }" # Index 7: Create empty result object in r9
- "ComprehensionBegin { params_index: 0 }" # Index 8: Start object comprehension
- "LoopStart { params_index: 0 }" # Index 9: Start loop
- "ComprehensionYield { value_reg: 5, key_reg: 5 }" # Index 10: Use value as both key and value
- "LoopNext { body_start: 10, loop_end: 12 }" # Index 11: Continue loop
- "Return { value: 9 }" # Index 12: Return result object
want_result: {1: 1, null: null, 2: 2}

View File

@@ -0,0 +1,139 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Set Comprehension Test Suite
# Tests set comprehensions - collect unique transformed values based on conditions
# Corresponds to Rego's "{transform | condition}" patterns
cases:
- note: set_simple_transform
description: Simple set comprehension with transformation
example_rego: |
# Transform array values into set - duplicates removed
{x * 2 | x := [1, 2, 2, 3][_]} # {2, 4, 6} (duplicates removed)
literals:
- 1
- 2
- 3
- 2 # multiplier
instruction_params:
comprehension_start_params:
- mode: "Set"
collection_reg: 0
key_reg: 4
value_reg: 5
result_reg: 7
body_start: 10
comprehension_end: 14
instructions:
- "ArrayNew { dest: 0 }" # Create input array [1, 2, 2, 3] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "ArrayPush { arr: 0, value: 2 }" # Push 2 to array
- "ArrayPush { arr: 0, value: 2 }" # Push 2 again to array (duplicate)
- "Load { dest: 3, literal_idx: 2 }" # Load 3 into register 3
- "ArrayPush { arr: 0, value: 3 }" # Push 3 to array
- "SetNew { dest: 7 }" # Initialize result set in register 7
- "ComprehensionStart { params_index: 0 }" # Start set comprehension
- "Load { dest: 6, literal_idx: 3 }" # Load multiplier 2 into register 6
- "Mul { dest: 10, left: 5, right: 6 }" # Multiply current value by 2, store result in register 10
- "ComprehensionAdd { value_reg: 10 }" # Add transformed value to result set (auto-deduplicates)
- "Halt" # End comprehension
- "Return { value: 7 }" # Return result set
want_result:
set!: [2, 4, 6]
- note: set_empty_input
description: Set comprehension with empty input
example_rego: |
# Transform empty array into set
{x + 5 | x := [][_]} # {} (empty set)
literals:
- 5 # addend
instruction_params:
comprehension_start_params:
- mode: "Set"
collection_reg: 0
key_reg: 4
value_reg: 5
result_reg: 7
body_start: 3
comprehension_end: 7
instructions:
- "ArrayNew { dest: 0 }" # Create empty input array in register 0
- "SetNew { dest: 7 }" # Initialize result set in register 7
- "ComprehensionStart { params_index: 0 }" # Start set comprehension
- "Load { dest: 6, literal_idx: 0 }" # Load addend 5 into register 6
- "Add { dest: 10, left: 5, right: 6 }" # Add 5 to current value, store result in register 10
- "ComprehensionAdd { value_reg: 10 }" # Add transformed value to result set
- "Halt" # End comprehension
- "Return { value: 7 }" # Return result set
want_result:
set!: []
- note: set_single_element
description: Set comprehension with single element
example_rego: |
# Transform single element into set
{x - 1 | x := [10][_]} # {9}
literals:
- 10
- 1 # subtrahend
instruction_params:
comprehension_start_params:
- mode: "Set"
collection_reg: 0
key_reg: 4
value_reg: 5
result_reg: 7
body_start: 5
comprehension_end: 9
instructions:
- "ArrayNew { dest: 0 }" # Create input array [10] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 10 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 10 to array
- "SetNew { dest: 7 }" # Initialize result set in register 7
- "ComprehensionStart { params_index: 0 }" # Start set comprehension
- "Load { dest: 6, literal_idx: 1 }" # Load subtrahend 1 into register 6
- "Sub { dest: 10, left: 5, right: 6 }" # Subtract 1 from current value, store result in register 10
- "ComprehensionAdd { value_reg: 10 }" # Add transformed value to result set
- "Halt" # End comprehension
- "Return { value: 7 }" # Return result set
want_result:
set!: [9]
- note: set_with_null_deduplication
description: Set comprehension with null values and deduplication
example_rego: |
# Collect unique values including nulls
{x | x := [1, null, 1, null, 2][_]} # {1, null, 2}
literals:
- 1
- 2
instruction_params:
comprehension_start_params:
- mode: "Set"
collection_reg: 0
key_reg: 4
value_reg: 5
result_reg: 7
body_start: 11
comprehension_end: 13
instructions:
- "ArrayNew { dest: 0 }" # Create input array in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "LoadNull { dest: 2 }" # Load null value
- "ArrayPush { arr: 0, value: 2 }" # Push null to array
- "ArrayPush { arr: 0, value: 1 }" # Push 1 again (duplicate)
- "ArrayPush { arr: 0, value: 2 }" # Push null again (duplicate)
- "Load { dest: 3, literal_idx: 1 }" # Load 2
- "ArrayPush { arr: 0, value: 3 }" # Push 2 to array
- "SetNew { dest: 7 }" # Initialize result set in register 7
- "ComprehensionStart { params_index: 0 }" # Start set comprehension
- "ComprehensionAdd { value_reg: 5 }" # Add current value to result set (auto-deduplicates)
- "Halt" # End comprehension
- "Return { value: 7 }" # Return result set
want_result:
set!: [1, null, 2]

View File

@@ -0,0 +1,143 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Universal Loops Test Suite
# Tests universal quantification - succeed if ALL elements satisfy the condition
# Corresponds to Rego's "every x in collection; condition" patterns
cases:
- note: universal_basic_every
description: Basic universal quantification - every element satisfies condition
example_rego: |
# Check if every element in array is greater than 0
every x in [1, 2, 3] {
x > 0 # true (all elements > 0)
}
literals:
- 1
- 2
- 3
- 0 # comparison value
instruction_params:
loop_params:
- mode: "Every"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 8
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Create input array [1, 2, 3] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "ArrayPush { arr: 0, value: 2 }" # Push 2 to array
- "Load { dest: 3, literal_idx: 2 }" # Load 3 into register 3
- "ArrayPush { arr: 0, value: 3 }" # Push 3 to array
- "LoopStart { params_index: 0 }" # Start universal loop using parameter table index 0
- "Load { dest: 7, literal_idx: 3 }" # Load comparison value 0 into register 7
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 0
- "AssertCondition { condition: 8 }" # Assert the condition result for universal logic
- "LoopNext { body_start: 8, loop_end: 12 }" # Continue to next iteration or exit early if condition fails
- "Return { value: 6 }" # Return result (true if all elements satisfied condition)
want_result: true
- note: universal_one_fails
description: Universal quantification where one element fails condition
example_rego: |
# Check if every element in array is greater than 1
every x in [1, 2, 3] {
x > 1 # false (1 is not > 1)
}
literals:
- 1
- 2
- 3
- 1 # comparison value
instruction_params:
loop_params:
- mode: "Every"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 8
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Create input array [1, 2, 3] in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 1 into register 1
- "ArrayPush { arr: 0, value: 1 }" # Push 1 to array
- "Load { dest: 2, literal_idx: 1 }" # Load 2 into register 2
- "ArrayPush { arr: 0, value: 2 }" # Push 2 to array
- "Load { dest: 3, literal_idx: 2 }" # Load 3 into register 3
- "ArrayPush { arr: 0, value: 3 }" # Push 3 to array
- "LoopStart { params_index: 0 }" # Start universal loop using parameter table index 0
- "Load { dest: 7, literal_idx: 3 }" # Load comparison value 1 into register 7
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 1
- "AssertCondition { condition: 8 }" # Assert the condition result for universal logic
- "LoopNext { body_start: 8, loop_end: 12 }" # Continue to next iteration or exit early on failure
- "Return { value: 6 }" # Return result (false since first element failed condition)
want_result: false
- note: universal_empty_collection
description: Universal quantification on empty collection
example_rego: |
# Check if every element in empty array satisfies condition
every x in [] {
x > 0 # true (vacuously true - all 0 elements satisfy condition)
}
literals:
- 0 # comparison value
instruction_params:
loop_params:
- mode: "Every"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 2
loop_end: 5
instructions:
- "ArrayNew { dest: 0 }" # Create empty input array in register 0
- "LoopStart { params_index: 0 }" # Start universal loop
- "Load { dest: 7, literal_idx: 0 }" # Load comparison value 0 into register 7
- "Gt { dest: 8, left: 5, right: 7 }" # Check if current value > 0
- "LoopNext { body_start: 2, loop_end: 5 }" # Continue to next iteration
- "Return { value: 6 }" # Return result (true for empty collection - vacuous truth)
want_result: true
- note: universal_null_handling
description: Universal quantification with null values
example_rego: |
# Test behavior with null values - should handle gracefully
every x in [2, null, 4] {
x != null # false (null fails the condition)
}
literals:
- 2
- 4
instruction_params:
loop_params:
- mode: "Every"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 8
loop_end: 12
instructions:
- "ArrayNew { dest: 0 }" # Create input array in register 0
- "Load { dest: 1, literal_idx: 0 }" # Load 2
- "ArrayPush { arr: 0, value: 1 }" # Push 2 to array
- "LoadNull { dest: 2 }" # Load null value
- "ArrayPush { arr: 0, value: 2 }" # Push null to array
- "Load { dest: 3, literal_idx: 1 }" # Load 4
- "ArrayPush { arr: 0, value: 3 }" # Push 4 to array
- "LoopStart { params_index: 0 }" # Start universal loop
- "LoadNull { dest: 7 }" # Load null for comparison
- "Ne { dest: 8, left: 5, right: 7 }" # Check if current value != null
- "AssertCondition { condition: 8 }" # Assert the condition result for universal logic
- "LoopNext { body_start: 8, loop_end: 12 }" # Continue to next iteration
- "Return { value: 6 }" # Return result
want_result: false

View File

@@ -0,0 +1,376 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Null and Undefined Handling Test Suite
# Tests null and undefined behavior across all instruction families
# Covers arithmetic, comparisons, logical ops, indexing, loops, and comprehensions
cases:
- note: load_null_basic
description: LoadNull loads null value
example_rego: "null"
literals: []
instructions:
- "LoadNull { dest: 0 }"
- "Return { value: 0 }"
want_result: null
- note: null_in_arithmetic_add
description: Adding null is a type error
example_rego: "null + 1"
literals:
- 1
instructions:
- "LoadNull { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot add Null"
- note: null_in_arithmetic_sub
description: Subtracting null is a type error
example_rego: "5 - null"
literals:
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadNull { dest: 1 }"
- "Sub { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot subtract Number(5)"
- note: null_in_arithmetic_mul
description: Multiplying null is a type error
example_rego: "null * 3"
literals:
- 3
instructions:
- "LoadNull { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Mul { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot multiply Null"
- note: null_in_comparison_eq
description: null equals null
example_rego: "null == null"
literals: []
instructions:
- "LoadNull { dest: 0 }"
- "LoadNull { dest: 1 }"
- "Eq { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: null_not_equal_to_number
description: null is not equal to numbers
example_rego: "null == 0"
literals:
- 0
instructions:
- "LoadNull { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Eq { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: false
- note: null_not_equal_to_false
description: null is not equal to false
example_rego: "null == false"
literals: []
instructions:
- "LoadNull { dest: 0 }"
- "LoadFalse { dest: 1 }"
- "Eq { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: false
- note: null_in_comparison_lt
description: Ordering comparison treats null as less than numbers
example_rego: "null < 5"
literals:
- 5
instructions:
- "LoadNull { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Lt { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: null_in_logical_and
description: Logical AND treats null as truthy
example_rego: "null && true"
literals: []
instructions:
- "LoadNull { dest: 0 }"
- "LoadTrue { dest: 1 }"
- "And { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: null_in_logical_or
description: Logical OR treats null as truthy
example_rego: "null || false"
literals: []
instructions:
- "LoadNull { dest: 0 }"
- "LoadFalse { dest: 1 }"
- "Or { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: true
- note: null_in_logical_not
description: Logical NOT treats null as truthy (returns false)
example_rego: "not null"
literals: []
instructions:
- "LoadNull { dest: 0 }"
- "Not { dest: 1, operand: 0 }"
- "Return { value: 1 }"
want_result: false
- note: null_as_array_index
description: Indexing array with null key
example_rego: "[1, 2, 3][null]"
literals:
- [1, 2, 3]
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadNull { dest: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined" # null is not a valid array index
- note: null_as_object_key
description: Indexing object with null key
example_rego: "{\"a\": 1, \"b\": 2}[null]"
literals:
- {"a": 1, "b": 2}
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadNull { dest: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined" # null key doesn't exist
- note: null_in_contains_check
description: Contains check with null
example_rego: "null in [1, 2, null, 3]"
literals:
- [1, 2, null, 3]
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadNull { dest: 1 }"
- "Contains { dest: 2, collection: 0, value: 1 }"
- "Return { value: 2 }"
want_result: true
- note: null_in_set
description: null can be a set member
example_rego: "{1, null, 3}"
literals:
- 1
- 3
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "SetAdd { set: 0, value: 1 }"
- "LoadNull { dest: 2 }"
- "SetAdd { set: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 1 }"
- "SetAdd { set: 0, value: 3 }"
- "Return { value: 0 }"
want_result:
set!:
- 1
- null
- 3
- note: null_in_array
description: null can be an array element
example_rego: "[1, null, 3]"
literals:
- 1
- 3
instruction_params:
array_create_params:
- dest: 0
elements: [1, 2, 3]
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "LoadNull { dest: 2 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ArrayCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result: [1, null, 3]
- note: null_in_object_value
description: null can be an object value
example_rego: "{\"a\": 1, \"b\": null}"
literals:
- "a"
- 1
- "b"
- {}
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 3
literal_key_fields: []
fields:
- [1, 2]
- [3, 4]
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "LoadNull { dest: 4 }"
- "ObjectCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result: {"a": 1, "b": null}
- note: undefined_in_arithmetic
description: Arithmetic with undefined register produces undefined
example_rego: "undefined_var + 1"
literals:
- 1
instructions:
# r0 is undefined (not loaded)
- "Load { dest: 1, literal_idx: 0 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: undefined_in_comparison
description: Comparison with undefined returns undefined
example_rego: "undefined_var == 5"
literals:
- 5
instructions:
# r0 is undefined
- "Load { dest: 1, literal_idx: 0 }"
- "Eq { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: undefined_in_logical_ops
description: Logical operations with undefined return undefined
example_rego: "undefined_var && true"
literals: []
instructions:
# r0 is undefined
- "LoadTrue { dest: 1 }"
- "And { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: undefined_indexing
description: Indexing undefined returns undefined
example_rego: "undefined_var[\"key\"]"
literals:
- "key"
instructions:
# r0 is undefined
- "Load { dest: 1, literal_idx: 0 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: undefined_in_array_create
description: ArrayCreate with undefined element returns undefined
literals:
- 1
- 2
instruction_params:
array_create_params:
- dest: 0
elements: [1, 2, 3] # r3 is undefined
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
# r3 is undefined
- "ArrayCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result: "#undefined"
- note: undefined_in_object_create_key
description: ObjectCreate with undefined key returns undefined
literals:
- 1
- 2
- {}
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 2
literal_key_fields: []
fields:
- [1, 2]
- [3, 4]
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
# r3, r4 are undefined
- "ObjectCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result: "#undefined"
- note: undefined_in_object_create_value
description: ObjectCreate with undefined value returns undefined
literals:
- "key1"
- "key2"
- 1
- {}
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 3
literal_key_fields: []
fields:
- [1, 3]
- [2, 4] # r4 is undefined
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
# r4 is undefined
- "ObjectCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result: "#undefined"
- note: undefined_in_loop_collection
description: Loop over undefined collection fails gracefully
literals: []
instruction_params:
loop_params:
- mode: "ForEach"
collection: 0 # r0 is undefined
key_reg: 1
value_reg: 2
result_reg: 4
body_start: 1
loop_end: 3
instructions:
# r0 is undefined
- "LoopStart { params_index: 0 }"
# Loop body (never executed because collection is undefined)
- "LoadTrue { dest: 3 }"
- "LoopNext { body_start: 1, loop_end: 3 }"
- "Return { value: 3 }"
want_result: "#undefined" # Loop over undefined collection yields undefined
- note: undefined_propagation_through_chain
description: Undefined propagates through operation chain
example_rego: "(undefined_var + 1) * 2"
literals:
- 1
- 2
instructions:
# r0 is undefined
- "Load { dest: 1, literal_idx: 0 }"
- "Add { dest: 2, left: 0, right: 1 }" # r2 becomes undefined
- "Load { dest: 3, literal_idx: 1 }"
- "Mul { dest: 4, left: 2, right: 3 }" # r4 becomes undefined
- "Return { value: 4 }"
want_result: "#undefined"

View File

@@ -0,0 +1,276 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Object Operations Test Suite
# Tests advanced object creation, manipulation, and edge cases
# Covers dynamic keys, collisions, non-string keys, and template validation
cases:
- note: object_key_collision_overwrite
description: Setting same key twice should overwrite the value
example_rego: "{\"key\": 1, \"key\": 2}"
literals:
- {}
- "key"
- 1
- 2
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }" # key
- "Load { dest: 2, literal_idx: 2 }" # value 1
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Load { dest: 3, literal_idx: 3 }" # value 2
- "ObjectSet { obj: 0, key: 1, value: 3 }" # Overwrite
- "Return { value: 0 }"
want_result: {"key": 2}
- note: object_dynamic_key_generation
description: Generate object keys dynamically from loop iteration
example_rego: "{sprintf(\"key_%d\", [i]): i | i := [1, 2][_]}"
literals:
- {}
- 1
- 2
- "key_1"
- "key_2"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
loop_params:
- mode: "ForEach"
collection: 5
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 7
loop_end: 13
instructions:
- "ObjectCreate { params_index: 0 }"
- "ArrayNew { dest: 5 }"
- "Load { dest: 1, literal_idx: 1 }"
- "ArrayPush { arr: 5, value: 1 }"
- "Load { dest: 2, literal_idx: 2 }"
- "ArrayPush { arr: 5, value: 2 }"
- "LoopStart { params_index: 0 }"
# Generate dynamic key based on value
- "Load { dest: 20, literal_idx: 3 }" # "key_1" when i=1
- "Load { dest: 21, literal_idx: 4 }" # "key_2" when i=2
# For simplicity, we'll set both keys
- "ObjectSet { obj: 0, key: 20, value: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ObjectSet { obj: 0, key: 21, value: 3 }"
- "LoopNext { body_start: 7, loop_end: 13 }"
- "Return { value: 0 }"
want_result: {"key_1": 1, "key_2": 2}
- note: object_number_keys
description: Object with number keys
example_rego: "{1: \"one\", 2: \"two\", 42: \"answer\"}"
literals:
- {}
- 1
- "one"
- 2
- "two"
- 42
- "answer"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }" # key 1
- "Load { dest: 2, literal_idx: 2 }" # value "one"
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Load { dest: 3, literal_idx: 3 }" # key 2
- "Load { dest: 4, literal_idx: 4 }" # value "two"
- "ObjectSet { obj: 0, key: 3, value: 4 }"
- "Load { dest: 5, literal_idx: 5 }" # key 42
- "Load { dest: 6, literal_idx: 6 }" # value "answer"
- "ObjectSet { obj: 0, key: 5, value: 6 }"
- "Return { value: 0 }"
want_result: {1: "one", 2: "two", 42: "answer"}
- note: object_boolean_keys
description: Object with boolean keys
example_rego: "{true: \"yes\", false: \"no\"}"
literals:
- {}
- "yes"
- "no"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "LoadTrue { dest: 1 }"
- "Load { dest: 2, literal_idx: 1 }" # value "yes"
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "LoadFalse { dest: 3 }"
- "Load { dest: 4, literal_idx: 2 }" # value "no"
- "ObjectSet { obj: 0, key: 3, value: 4 }"
- "Return { value: 0 }"
want_result: {true: "yes", false: "no"}
- note: object_null_key
description: Object with null key
example_rego: "{null: \"nothing\"}"
literals:
- {}
- "nothing"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "LoadNull { dest: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Return { value: 0 }"
want_result: {null: "nothing"}
- note: object_empty_string_key
description: Object with empty string key
example_rego: "{\"\": \"empty_key\"}"
literals:
- {}
- ""
- "empty_key"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }" # empty string key
- "Load { dest: 2, literal_idx: 2 }" # value
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Return { value: 0 }"
want_result: {"": "empty_key"}
- note: object_set_undefined_value
description: Setting undefined value in object keeps it
literals:
- {}
- "key"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
# r2 is undefined (never loaded)
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Return { value: 0 }"
want_result: {"key": "#undefined"}
- note: object_create_with_template
description: ObjectCreate with pre-populated template
literals:
- {"existing": "value", "num": 42}
- "new_key"
- "new_value"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Load { dest: 2, literal_idx: 2 }"
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Return { value: 0 }"
want_result: {"existing": "value", "num": 42, "new_key": "new_value"}
- note: object_nested_structure
description: Create deeply nested object structure
example_rego: "{\"outer\": {\"middle\": {\"inner\": \"value\"}}}"
literals:
- {}
- "outer"
- "middle"
- "inner"
- "value"
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }" # outer
- "Load { dest: 10, literal_idx: 0 }" # middle object
- "Load { dest: 11, literal_idx: 0 }" # inner object
- "Load { dest: 12, literal_idx: 3 }" # "inner" key
- "Load { dest: 13, literal_idx: 4 }" # "value"
- "ObjectSet { obj: 11, key: 12, value: 13 }" # {inner: "value"}
- "Load { dest: 14, literal_idx: 2 }" # "middle" key
- "ObjectSet { obj: 10, key: 14, value: 11 }" # {middle: {...}}
- "Load { dest: 15, literal_idx: 1 }" # "outer" key
- "ObjectSet { obj: 0, key: 15, value: 10 }" # {outer: {...}}
- "Return { value: 0 }"
want_result: {"outer": {"middle": {"inner": "value"}}}
- note: object_mixed_value_types
description: Object with values of different types
example_rego: "{\"str\": \"text\", \"num\": 42, \"bool\": true, \"null\": null, \"arr\": [1, 2]}"
literals:
- {}
- "str"
- "text"
- "num"
- 42
- "bool"
- "null"
- "arr"
- [1, 2]
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }" # "str"
- "Load { dest: 2, literal_idx: 2 }" # "text"
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Load { dest: 3, literal_idx: 3 }" # "num"
- "Load { dest: 4, literal_idx: 4 }" # 42
- "ObjectSet { obj: 0, key: 3, value: 4 }"
- "Load { dest: 5, literal_idx: 5 }" # "bool"
- "LoadTrue { dest: 6 }"
- "ObjectSet { obj: 0, key: 5, value: 6 }"
- "Load { dest: 7, literal_idx: 6 }" # "null"
- "LoadNull { dest: 8 }"
- "ObjectSet { obj: 0, key: 7, value: 8 }"
- "Load { dest: 9, literal_idx: 7 }" # "arr"
- "Load { dest: 10, literal_idx: 8 }" # [1, 2]
- "ObjectSet { obj: 0, key: 9, value: 10 }"
- "Return { value: 0 }"
want_result: {"str": "text", "num": 42, "bool": true, "null": null, "arr": [1, 2]}

View File

@@ -0,0 +1,165 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Predefined Global Bindings Test Suite
# Tests Rego's predefined data and input global bindings
# These bindings are always available in Rego policies
cases:
- note: load_data_basic
description: Test loading global data object
data:
users: ["alice", "bob"]
config:
debug: true
timeout: 30
input: null
literals: ["users"]
instructions:
- "LoadData { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # Load "users" literal
- "Index { dest: 2, container: 0, key: 1 }" # data.users
- "Return { value: 2 }"
want_result: ["alice", "bob"]
- note: load_input_basic
description: Test loading global input object
data: null
input:
request:
method: "GET"
path: "/api/users"
user:
id: 123
role: "admin"
literals: ["request", "method"]
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # Load "request" literal
- "Index { dest: 2, container: 0, key: 1 }" # input.request
- "Load { dest: 3, literal_idx: 1 }" # Load "method" literal
- "Index { dest: 4, container: 2, key: 3 }" # input.request.method
- "Return { value: 4 }"
want_result: "GET"
- note: data_and_input_combined
description: Test using both data and input in same expression
data:
permissions:
admin: ["read", "write", "delete"]
user: ["read"]
input:
user:
role: "admin"
literals: ["permissions", "user", "role"]
instructions:
- "LoadData { dest: 0 }" # Load data
- "LoadInput { dest: 1 }" # Load input
- "Load { dest: 2, literal_idx: 1 }" # Load "user" literal
- "Index { dest: 3, container: 1, key: 2 }" # input.user
- "Load { dest: 4, literal_idx: 2 }" # Load "role" literal
- "Index { dest: 5, container: 3, key: 4 }" # input.user.role
- "Load { dest: 6, literal_idx: 0 }" # Load "permissions" literal
- "Index { dest: 7, container: 0, key: 6 }" # data.permissions
- "Index { dest: 8, container: 7, key: 5 }" # data.permissions[input.user.role]
- "Return { value: 8 }"
want_result: ["read", "write", "delete"]
- note: data_null_handling
description: Test behavior when data is null
data: null
input:
test: "value"
literals: []
instructions:
- "LoadData { dest: 0 }"
- "Return { value: 0 }"
want_result: null
- note: input_null_handling
description: Test behavior when input is null
data:
test: "value"
input: null
literals: []
instructions:
- "LoadInput { dest: 0 }"
- "Return { value: 0 }"
want_result: null
- note: nested_data_access
description: Test deep nested data access
data:
api:
v1:
endpoints:
users: "/api/v1/users"
posts: "/api/v1/posts"
input: null
literals: ["api", "v1", "endpoints", "users"]
instructions:
- "LoadData { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # "api"
- "Index { dest: 2, container: 0, key: 1 }" # data.api
- "Load { dest: 3, literal_idx: 1 }" # "v1"
- "Index { dest: 4, container: 2, key: 3 }" # data.api.v1
- "Load { dest: 5, literal_idx: 2 }" # "endpoints"
- "Index { dest: 6, container: 4, key: 5 }" # data.api.v1.endpoints
- "Load { dest: 7, literal_idx: 3 }" # "users"
- "Index { dest: 8, container: 6, key: 7 }" # data.api.v1.endpoints.users
- "Return { value: 8 }"
want_result: "/api/v1/users"
- note: array_access_with_input
description: Test array indexing with input values
data:
colors: ["red", "green", "blue"]
input:
selected_index: 1
literals: ["colors", "selected_index"]
instructions:
- "LoadData { dest: 0 }"
- "LoadInput { dest: 1 }"
- "Load { dest: 2, literal_idx: 0 }" # "colors"
- "Index { dest: 3, container: 0, key: 2 }" # data.colors
- "Load { dest: 4, literal_idx: 1 }" # "selected_index"
- "Index { dest: 5, container: 1, key: 4 }" # input.selected_index
- "Index { dest: 6, container: 3, key: 5 }" # data.colors[input.selected_index]
- "Return { value: 6 }"
want_result: "green"
- note: data_only_access
description: Test accessing data when input is not needed
data:
settings:
theme: "dark"
notifications: true
input: null
literals: ["settings", "theme"]
instructions:
- "LoadData { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # "settings"
- "Index { dest: 2, container: 0, key: 1 }" # data.settings
- "Load { dest: 3, literal_idx: 1 }" # "theme"
- "Index { dest: 4, container: 2, key: 3 }" # data.settings.theme
- "Return { value: 4 }"
want_result: "dark"
- note: input_only_access
description: Test accessing input when data is not needed
data: null
input:
request:
headers:
authorization: "Bearer token123"
literals: ["request", "headers", "authorization"]
instructions:
- "LoadInput { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # "request"
- "Index { dest: 2, container: 0, key: 1 }" # input.request
- "Load { dest: 3, literal_idx: 1 }" # "headers"
- "Index { dest: 4, container: 2, key: 3 }" # input.request.headers
- "Load { dest: 5, literal_idx: 2 }" # "authorization"
- "Index { dest: 6, container: 4, key: 5 }" # input.request.headers.authorization
- "Return { value: 6 }"
want_result: "Bearer token123"

View File

@@ -0,0 +1,217 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Resource Limits Test Suite
# Tests instruction count limits, recursion depth, and resource exhaustion scenarios
# Verifies VM handles resource constraints gracefully
cases:
- note: instruction_limit_in_simple_loop
description: Instruction limit exceeded in simple loop
example_rego: "some x in [1, 2, 3, 4, 5]; x > 0"
literals:
- 1
- 2
- 3
- 4
- 5
- 0
max_instructions: 10 # Limit low enough that execution exceeds it before completion
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 13
loop_end: 17
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayPush { arr: 0, value: 3 }"
- "Load { dest: 4, literal_idx: 3 }"
- "ArrayPush { arr: 0, value: 4 }"
- "Load { dest: 5, literal_idx: 4 }"
- "ArrayPush { arr: 0, value: 5 }"
- "LoopStart { params_index: 0 }"
- "Load { dest: 13, literal_idx: 5 }"
- "Gt { dest: 14, left: 11, right: 13 }"
- "AssertCondition { condition: 14 }"
- "LoopNext { body_start: 13, loop_end: 17 }"
- "Return { value: 12 }"
want_error: "exceeded maximum instruction limit"
- note: instruction_limit_in_comprehension
description: Instruction limit exceeded during comprehension
example_rego: "[x | x := [1, 2, 3, 4, 5][_]]"
literals:
- 1
- 2
- 3
- 4
- 5
max_instructions: 25
instruction_params:
comprehension_begin_params:
- mode: "Array"
collection_reg: 0
result_reg: 0
key_reg: 10
value_reg: 11
body_start: 13
comprehension_end: 17
loop_params:
- mode: "ForEach"
collection: 6
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 13
loop_end: 17
instructions:
- "ArrayNew { dest: 6 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 6, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 6, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayPush { arr: 6, value: 3 }"
- "Load { dest: 4, literal_idx: 3 }"
- "ArrayPush { arr: 6, value: 4 }"
- "Load { dest: 5, literal_idx: 4 }"
- "ArrayPush { arr: 6, value: 5 }"
- "ComprehensionBegin { params_index: 0 }"
- "LoopStart { params_index: 0 }"
- "ComprehensionYield { value_reg: 11 }"
- "LoopNext { body_start: 13, loop_end: 17 }"
- "ComprehensionEnd"
- "Return { value: 0 }"
want_error: "exceeded maximum instruction limit"
- note: instruction_limit_in_nested_loops
description: Instruction limit exceeded in nested loops
example_rego: "some x in [1, 2]; some y in [3, 4]; x + y > 0"
literals:
- 1
- 2
- 3
- 4
- 0
max_instructions: 30
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 5
loop_end: 18
- mode: "Any"
collection: 2
key_reg: 20
value_reg: 21
result_reg: 22
body_start: 8
loop_end: 16
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "Load { dest: 3, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 3 }"
- "LoopStart { params_index: 0 }"
- "ArrayNew { dest: 2 }"
- "Load { dest: 4, literal_idx: 2 }"
- "ArrayPush { arr: 2, value: 4 }"
- "Load { dest: 5, literal_idx: 3 }"
- "ArrayPush { arr: 2, value: 5 }"
- "LoopStart { params_index: 1 }"
- "Add { dest: 30, left: 11, right: 21 }"
- "Load { dest: 31, literal_idx: 4 }"
- "Gt { dest: 32, left: 30, right: 31 }"
- "AssertCondition { condition: 32 }"
- "LoopNext { body_start: 8, loop_end: 16 }"
- "AssertCondition { condition: 22 }"
- "LoopNext { body_start: 5, loop_end: 18 }"
- "Return { value: 12 }"
want_error: "exceeded maximum instruction limit"
- note: large_literal_table_access
description: Access literal near u16 bounds (valid case)
literals:
- 42
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Return { value: 0 }"
want_result: 42
- note: literal_index_out_of_bounds
description: Literal index beyond table bounds should error
literals:
- 42
instructions:
- "Load { dest: 0, literal_idx: 999 }"
- "Return { value: 0 }"
want_error: "Literal index 999 out of bounds"
- note: instruction_limit_with_early_return
description: Instruction limit allows early successful completion
example_rego: "some x in [1, 2]; x == 1"
literals:
- 1
- 2
max_instructions: 200 # Allow enough headroom for both execution modes
instruction_params:
loop_params:
- mode: "Any"
collection: 0
key_reg: 10
value_reg: 11
result_reg: 12
body_start: 6
loop_end: 9
instructions:
- "ArrayNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "ArrayPush { arr: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "ArrayPush { arr: 0, value: 2 }"
- "LoopStart { params_index: 0 }"
- "Load { dest: 13, literal_idx: 0 }"
- "Eq { dest: 14, left: 11, right: 13 }"
- "AssertCondition { condition: 14 }"
- "LoopNext { body_start: 6, loop_end: 9 }"
- "Return { value: 12 }"
want_result: true
- note: many_registers_usage
description: Test using high register numbers near upper bound without error
example_rego: "Store values in registers near VM upper bound"
literals:
- 1
- 2
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 25, literal_idx: 1 }"
- "Load { dest: 49, literal_idx: 2 }"
- "Add { dest: 30, left: 0, right: 25 }"
- "Add { dest: 48, left: 30, right: 49 }"
- "Return { value: 48 }"
want_result: 6
- note: zero_instruction_limit
description: Zero instruction limit should error immediately
literals:
- 42
max_instructions: 0
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Return { value: 0 }"
want_error: "exceeded maximum instruction limit"

View File

@@ -0,0 +1,423 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Serialization Test Suite
# Tests round-trip serialization of compiled RVM programs
# Covers all instruction types, large programs, and edge cases
cases:
- note: serialization_basic_arithmetic
description: Serialize and deserialize simple arithmetic program
example_rego: "5 + 3"
literals:
- 5
- 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: 8
- note: serialization_comparisons
description: Serialize comparison instructions
example_rego: "10 > 5 && 3 < 7"
literals:
- 10
- 5
- 3
- 7
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Gt { dest: 2, left: 0, right: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Load { dest: 4, literal_idx: 3 }"
- "Lt { dest: 5, left: 3, right: 4 }"
- "And { dest: 6, left: 2, right: 5 }"
- "Return { value: 6 }"
want_result: true
- note: serialization_array_create
description: Serialize ArrayCreate with instruction_params
example_rego: "[1, 2, 3]"
literals:
- 1
- 2
- 3
instruction_params:
array_create_params:
- dest: 0
elements: [1, 2, 3]
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result: [1, 2, 3]
- note: serialization_object_create
description: Serialize ObjectCreate with complex params
example_rego: "{\"a\": 1, \"b\": 2}"
literals:
- "a"
- 1
- "b"
- 2
- {}
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 4
literal_key_fields: []
fields:
- [1, 2]
- [3, 4]
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Load { dest: 4, literal_idx: 3 }"
- "ObjectCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result: {"a": 1, "b": 2}
- note: serialization_set_operations
description: Serialize set creation and operations
example_rego: "{1, 2, 3}"
literals:
- 1
- 2
- 3
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "SetAdd { set: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "SetAdd { set: 0, value: 3 }"
- "Return { value: 0 }"
want_result:
set!:
- 1
- 2
- 3
- note: serialization_loop_foreach
description: Serialize ForEach loop with params
example_rego: "[x | x = [1, 2, 3][_]]"
literals:
- 1
- 2
- 3
instruction_params:
array_create_params:
- dest: 0
elements: [1, 2, 3]
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 9
body_start: 6
loop_end: 8
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayCreate { params_index: 0 }"
- "ArrayNew { dest: 6 }"
- "LoopStart { params_index: 0 }"
- "ArrayPush { arr: 6, value: 5 }"
- "LoopNext { body_start: 6, loop_end: 8 }"
- "Return { value: 6 }"
want_result: [1, 2, 3]
- note: serialization_loop_any
description: Serialize Any loop
example_rego: "some x in [1, 2, 3]; x > 2"
literals:
- 1
- 2
- 3
instruction_params:
array_create_params:
- dest: 0
elements: [1, 2, 3]
loop_params:
- mode: "Existential"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 6
body_start: 5
loop_end: 8
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayCreate { params_index: 0 }"
- "LoopStart { params_index: 0 }"
- "Gt { dest: 8, left: 5, right: 2 }"
- "AssertCondition { condition: 8 }"
- "LoopNext { body_start: 5, loop_end: 8 }"
- "Return { value: 6 }"
want_result: true
- note: serialization_comprehension_array
description: Serialize array comprehension
example_rego: "[x * 2 | x = [1, 2, 3][_]]"
literals:
- 1
- 2
- 3
instruction_params:
array_create_params:
- dest: 0
elements: [1, 2, 3]
loop_params:
- mode: "ForEach"
collection: 0
key_reg: 4
value_reg: 5
result_reg: 9
body_start: 6
loop_end: 9
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "ArrayCreate { params_index: 0 }"
- "ArrayNew { dest: 7 }"
- "LoopStart { params_index: 0 }"
- "Mul { dest: 6, left: 5, right: 2 }"
- "ArrayPush { arr: 7, value: 6 }"
- "LoopNext { body_start: 6, loop_end: 9 }"
- "Return { value: 7 }"
want_result: [2, 4, 6]
- note: serialization_indexed_access
description: Serialize indexing instructions
example_rego: "data.users[0].name"
literals:
- {"users": [{"name": "Alice"}, {"name": "Bob"}]}
- "users"
- 0
- "name"
instruction_params:
chained_index_params:
- dest: 4
root: 0
path_components:
- literal_idx: 1
- literal_idx: 2
- literal_idx: 3
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Load { dest: 2, literal_idx: 2 }"
- "Load { dest: 3, literal_idx: 3 }"
- "ChainedIndex { params_index: 0 }"
- "Return { value: 4 }"
want_result: "Alice"
- note: serialization_conditional_branching
description: Serialize conditional instructions
example_rego: "if true then 1 else 2"
literals:
- 1
- 2
instructions:
- "LoadTrue { dest: 0 }"
- "AssertCondition { condition: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Return { value: 1 }"
want_result: 1
- note: serialization_null_and_undefined
description: Serialize null and undefined handling
example_rego: "null"
literals: []
instructions:
- "LoadNull { dest: 0 }"
- "Return { value: 0 }"
want_result: null
- note: serialization_mixed_types
description: Serialize program with all value types
example_rego: "[1, \"text\", true, false, null, [2, 3], {\"k\": \"v\"}]"
literals:
- 1
- "text"
- 2
- 3
- "k"
- "v"
- {}
instruction_params:
array_create_params:
- dest: 6
elements: [3, 4]
- dest: 0
elements: [1, 2, 7, 8, 9, 6, 10]
object_create_params:
- dest: 10
template_literal_idx: 6
literal_key_fields: []
fields:
- [5, 11]
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Load { dest: 4, literal_idx: 3 }"
- "ArrayCreate { params_index: 0 }"
- "LoadTrue { dest: 7 }"
- "LoadFalse { dest: 8 }"
- "LoadNull { dest: 9 }"
- "Load { dest: 5, literal_idx: 4 }"
- "Load { dest: 11, literal_idx: 5 }"
- "ObjectCreate { params_index: 0 }"
- "ArrayCreate { params_index: 1 }"
- "Return { value: 0 }"
want_result: [1, "text", true, false, null, [2, 3], {"k": "v"}]
- note: serialization_large_program_50_instructions
description: Large program with many instructions (stress test)
example_rego: "Complex computation chain"
literals:
- 1
- 2
- 3
- 4
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "Mul { dest: 4, left: 2, right: 3 }"
- "Load { dest: 5, literal_idx: 3 }"
- "Sub { dest: 6, left: 4, right: 5 }"
- "Load { dest: 7, literal_idx: 4 }"
- "Div { dest: 8, left: 6, right: 7 }"
- "Load { dest: 9, literal_idx: 0 }"
- "Add { dest: 10, left: 8, right: 9 }"
- "Load { dest: 11, literal_idx: 1 }"
- "Mul { dest: 12, left: 10, right: 11 }"
- "Load { dest: 13, literal_idx: 2 }"
- "Add { dest: 14, left: 12, right: 13 }"
- "Load { dest: 15, literal_idx: 3 }"
- "Sub { dest: 16, left: 14, right: 15 }"
- "Load { dest: 17, literal_idx: 4 }"
- "Mul { dest: 18, left: 16, right: 17 }"
- "Load { dest: 19, literal_idx: 0 }"
- "Div { dest: 20, left: 18, right: 19 }"
- "Load { dest: 21, literal_idx: 1 }"
- "Add { dest: 22, left: 20, right: 21 }"
- "Load { dest: 23, literal_idx: 2 }"
- "Mul { dest: 24, left: 22, right: 23 }"
- "Load { dest: 25, literal_idx: 3 }"
- "Sub { dest: 26, left: 24, right: 25 }"
- "Load { dest: 27, literal_idx: 4 }"
- "Add { dest: 28, left: 26, right: 27 }"
- "Load { dest: 29, literal_idx: 0 }"
- "Mul { dest: 30, left: 28, right: 29 }"
- "Load { dest: 31, literal_idx: 1 }"
- "Div { dest: 32, left: 30, right: 31 }"
- "Load { dest: 33, literal_idx: 2 }"
- "Add { dest: 34, left: 32, right: 33 }"
- "Load { dest: 35, literal_idx: 3 }"
- "Sub { dest: 36, left: 34, right: 35 }"
- "Load { dest: 37, literal_idx: 4 }"
- "Mul { dest: 38, left: 36, right: 37 }"
- "Load { dest: 39, literal_idx: 0 }"
- "Add { dest: 40, left: 38, right: 39 }"
- "Load { dest: 41, literal_idx: 1 }"
- "Sub { dest: 42, left: 40, right: 41 }"
- "Load { dest: 43, literal_idx: 2 }"
- "Mul { dest: 44, left: 42, right: 43 }"
- "Load { dest: 45, literal_idx: 3 }"
- "Div { dest: 46, left: 44, right: 45 }"
- "Load { dest: 47, literal_idx: 4 }"
- "Add { dest: 48, left: 46, right: 47 }"
- "Return { value: 48 }"
want_result: 98
- note: serialization_large_literal_table
description: Program with many literal values
literals:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- "a"
- "b"
- "c"
- "d"
- "e"
- [1, 2, 3]
- {"key": "value"}
- true
- false
- null
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 5 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Load { dest: 3, literal_idx: 10 }"
- "Load { dest: 4, literal_idx: 15 }"
- "Return { value: 2 }"
want_result: 7
- note: serialization_nested_structures
description: Serialize deeply nested data structures
example_rego: "[{\"a\": [1, {\"b\": [2, 3]}]}]"
literals:
- 1
- 2
- 3
- "b"
- "a"
- {}
instruction_params:
array_create_params:
- dest: 3
elements: [2, 4]
- dest: 1
elements: [5, 6]
- dest: 0
elements: [7]
object_create_params:
- dest: 6
template_literal_idx: 5
literal_key_fields: []
fields:
- [8, 3]
- dest: 7
template_literal_idx: 5
literal_key_fields: []
fields:
- [9, 1]
instructions:
- "Load { dest: 5, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 4, literal_idx: 2 }"
- "ArrayCreate { params_index: 0 }"
- "Load { dest: 8, literal_idx: 3 }"
- "ObjectCreate { params_index: 0 }"
- "ArrayCreate { params_index: 1 }"
- "Load { dest: 9, literal_idx: 4 }"
- "ObjectCreate { params_index: 1 }"
- "ArrayCreate { params_index: 2 }"
- "Return { value: 0 }"
want_result: [{"a": [1, {"b": [2, 3]}]}]

View File

@@ -0,0 +1,284 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Set Operations Test Suite
# Tests set creation, deduplication, and membership testing
# Covers complex value deduplication, nested sets, and undefined handling
cases:
- note: set_deduplication_simple
description: Set automatically deduplicates simple values
example_rego: "{1, 2, 1, 3, 2}"
literals:
- 1
- 2
- 3
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # 1
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }" # 2
- "SetAdd { set: 0, value: 2 }"
- "SetAdd { set: 0, value: 1 }" # 1 again (duplicate)
- "Load { dest: 3, literal_idx: 2 }" # 3
- "SetAdd { set: 0, value: 3 }"
- "SetAdd { set: 0, value: 2 }" # 2 again (duplicate)
- "Return { value: 0 }"
want_result:
set!:
- 1
- 2
- 3
- note: set_deduplication_objects
description: Set deduplicates identical objects
example_rego: "{{\"a\": 1}, {\"b\": 2}, {\"a\": 1}}"
literals:
- {"a": 1}
- {"b": 2}
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # {"a": 1}
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }" # {"b": 2}
- "SetAdd { set: 0, value: 2 }"
- "SetAdd { set: 0, value: 1 }" # {"a": 1} again (duplicate)
- "Return { value: 0 }"
want_result:
set!:
- {"a": 1}
- {"b": 2}
- note: set_deduplication_arrays
description: Set deduplicates identical arrays
example_rego: "{[1, 2], [3, 4], [1, 2]}"
literals:
- [1, 2]
- [3, 4]
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # [1, 2]
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }" # [3, 4]
- "SetAdd { set: 0, value: 2 }"
- "SetAdd { set: 0, value: 1 }" # [1, 2] again (duplicate)
- "Return { value: 0 }"
want_result:
set!:
- [1, 2]
- [3, 4]
- note: set_with_mixed_types
description: Set can contain different types
example_rego: "{1, \"text\", true, null, [1, 2], {\"a\": 1}}"
literals:
- 1
- "text"
- [1, 2]
- {"a": 1}
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }" # 1
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }" # "text"
- "SetAdd { set: 0, value: 2 }"
- "LoadTrue { dest: 3 }"
- "SetAdd { set: 0, value: 3 }"
- "LoadNull { dest: 4 }"
- "SetAdd { set: 0, value: 4 }"
- "Load { dest: 5, literal_idx: 2 }" # [1, 2]
- "SetAdd { set: 0, value: 5 }"
- "Load { dest: 6, literal_idx: 3 }" # {"a": 1}
- "SetAdd { set: 0, value: 6 }"
- "Return { value: 0 }"
want_result:
set!:
- 1
- "text"
- true
- null
- [1, 2]
- {"a": 1}
- note: set_contains_simple
description: Contains check on set with simple values
example_rego: "2 in {1, 2, 3}"
literals:
- 1
- 2
- 3
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "SetAdd { set: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "SetAdd { set: 0, value: 3 }"
- "Contains { dest: 4, collection: 0, value: 2 }"
- "Return { value: 4 }"
want_result: true
- note: set_contains_object
description: Contains check with object value
example_rego: "{\"a\": 1} in {{\"a\": 1}, {\"b\": 2}}"
literals:
- {"a": 1}
- {"b": 2}
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "SetAdd { set: 0, value: 2 }"
- "Contains { dest: 3, collection: 0, value: 1 }"
- "Return { value: 3 }"
want_result: true
- note: set_contains_not_found
description: Contains returns false when value not in set
example_rego: "5 in {1, 2, 3}"
literals:
- 1
- 2
- 3
- 5
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "SetAdd { set: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "SetAdd { set: 0, value: 3 }"
- "Load { dest: 4, literal_idx: 3 }"
- "Contains { dest: 5, collection: 0, value: 4 }"
- "Return { value: 5 }"
want_result: false
- note: set_create_from_registers
description: SetCreate instruction creates set from multiple registers
literals:
- 1
- 2
- 3
instruction_params:
set_create_params:
- dest: 0
elements: [1, 2, 3, 1] # Duplicate 1
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }"
- "SetCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result:
set!:
- 1
- 2
- 3
- note: set_create_with_undefined_element
description: SetCreate with undefined element returns undefined (short-circuit)
literals:
- 1
- 2
- "#undefined"
instruction_params:
set_create_params:
- dest: 0
elements: [1, 2, 3] # r3 is undefined
instructions:
- "Load { dest: 1, literal_idx: 0 }"
- "Load { dest: 2, literal_idx: 1 }"
- "Load { dest: 3, literal_idx: 2 }" # r3 is explicitly undefined
- "SetCreate { params_index: 0 }"
- "Return { value: 0 }"
want_result: "#undefined"
- note: set_large_collection
description: Set with many elements (stress test)
literals:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "SetAdd { set: 0, value: 2 }"
- "Load { dest: 3, literal_idx: 2 }"
- "SetAdd { set: 0, value: 3 }"
- "Load { dest: 4, literal_idx: 3 }"
- "SetAdd { set: 0, value: 4 }"
- "Load { dest: 5, literal_idx: 4 }"
- "SetAdd { set: 0, value: 5 }"
- "Load { dest: 6, literal_idx: 5 }"
- "SetAdd { set: 0, value: 6 }"
- "Load { dest: 7, literal_idx: 6 }"
- "SetAdd { set: 0, value: 7 }"
- "Load { dest: 8, literal_idx: 7 }"
- "SetAdd { set: 0, value: 8 }"
- "Load { dest: 9, literal_idx: 8 }"
- "SetAdd { set: 0, value: 9 }"
- "Load { dest: 10, literal_idx: 9 }"
- "SetAdd { set: 0, value: 10 }"
- "Return { value: 0 }"
want_result:
set!:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- note: set_empty
description: Empty set creation
example_rego: "set()"
literals: []
instructions:
- "SetNew { dest: 0 }"
- "Return { value: 0 }"
want_result:
set!: []
- note: set_nested_in_set
description: Set containing other sets
example_rego: "{{1, 2}, {3, 4}}"
literals:
- set!:
- 1
- 2
- set!:
- 3
- 4
instructions:
- "SetNew { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "SetAdd { set: 0, value: 1 }"
- "Load { dest: 2, literal_idx: 1 }"
- "SetAdd { set: 0, value: 2 }"
- "Return { value: 0 }"
want_result:
set!:
-
set!:
- 1
- 2
-
set!:
- 3
- 4

View File

@@ -0,0 +1,224 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Type Errors Test Suite
# Tests graceful error handling for type mismatches across instruction families
# Verifies that VM returns appropriate errors instead of panicking
cases:
# Mixed-type arithmetic operations
- note: arithmetic_add_string_to_int
description: Adding string to int should error gracefully
example_rego: "1 + \"text\""
literals:
- 1
- "text"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot add"
- note: arithmetic_mul_bool_by_int
description: Multiplying boolean by int should error
example_rego: "true * 5"
literals:
- 5
instructions:
- "LoadTrue { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Mul { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot multiply"
- note: arithmetic_div_null_by_int
description: Dividing null by int should error
example_rego: "null / 2"
literals:
- 2
instructions:
- "LoadNull { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Div { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot divide"
- note: arithmetic_sub_array_from_int
description: Subtracting array from int should error
example_rego: "10 - [1, 2]"
literals:
- 10
- [1, 2]
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Sub { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot subtract"
- note: arithmetic_add_object_to_int
description: Adding object to int should error
example_rego: "5 + {\"a\": 1}"
literals:
- 5
- {"a": 1}
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Add { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "Cannot add"
# Logical operations on non-booleans
- note: logical_and_string_with_bool
description: AND with string operand should error
example_rego: "\"text\" && true"
literals:
- "text"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadTrue { dest: 1 }"
- "And { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "#undefined"
- note: logical_or_int_with_bool
description: OR with int operand should error
example_rego: "42 || false"
literals:
- 42
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "LoadFalse { dest: 1 }"
- "Or { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_error: "#undefined"
- note: logical_not_int
description: NOT with int operand should error
example_rego: "!42"
literals:
- 42
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Not { dest: 1, operand: 0 }"
- "Return { value: 1 }"
want_error: "#undefined"
# Invalid indexing operations
- note: index_int_with_string_key
description: Indexing int with string should return undefined
example_rego: "123[\"key\"]"
literals:
- 123
- "key"
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: index_null_with_int
description: Indexing null should return undefined
example_rego: "null[0]"
literals:
- 0
instructions:
- "LoadNull { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: index_bool_with_string
description: Indexing boolean should return undefined
example_rego: "true.field"
literals:
- "field"
instructions:
- "LoadTrue { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
- note: index_string_with_object_key
description: Indexing string with object key should return undefined
example_rego: "\"text\"[{}]"
literals:
- "text"
- {}
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Index { dest: 2, container: 0, key: 1 }"
- "Return { value: 2 }"
want_result: "#undefined"
# Contains with incompatible types
- note: contains_in_int
description: Contains check on int should return false
example_rego: "1 in 123"
literals:
- 123
- 1
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Contains { dest: 2, collection: 0, value: 1 }"
- "Return { value: 2 }"
want_result: false
- note: contains_in_bool
description: Contains check on boolean should return false
example_rego: "1 in true"
literals:
- 1
instructions:
- "LoadTrue { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Contains { dest: 2, collection: 0, value: 1 }"
- "Return { value: 2 }"
want_result: false
- note: contains_in_null
description: Contains check on null should return false
example_rego: "1 in null"
literals:
- 1
instructions:
- "LoadNull { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Contains { dest: 2, collection: 0, value: 1 }"
- "Return { value: 2 }"
want_result: false
# Comparison operations with incompatible types
- note: compare_string_lt_int
description: Comparing string < int returns ordering result in non-strict; errors in strict
example_rego: "\"abc\" < 5"
literals:
- "abc"
- 5
instructions:
- "Load { dest: 0, literal_idx: 0 }"
- "Load { dest: 1, literal_idx: 1 }"
- "Lt { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: false
want_error_strict: "#undefined"
- note: compare_bool_gt_array
description: Comparing bool > array returns ordering result in non-strict; errors in strict
example_rego: "true > [1, 2]"
literals:
- [1, 2]
instructions:
- "LoadTrue { dest: 0 }"
- "Load { dest: 1, literal_idx: 0 }"
- "Gt { dest: 2, left: 0, right: 1 }"
- "Return { value: 2 }"
want_result: false
want_error_strict: "#undefined"

View File

@@ -0,0 +1,274 @@
# Virtual Data Lookup Test Suite
# Exercises VirtualDataDocumentLookup across data/rule blending and errors.
cases:
- note: virtual_lookup_base_data_only
description: Lookup resolves to base data when no rules override
data:
services:
api:
enabled: true
literals:
- "services"
- "api"
- "enabled"
instruction_params:
virtual_data_document_lookup_params:
- dest: 3
path_components:
- literal_idx: 0
- literal_idx: 1
- literal_idx: 2
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 3 }"
want_result: true
- note: virtual_lookup_rule_override
description: Lookup combines rule result overriding base data
data:
services:
api:
enabled: false
literals:
- "services"
- "api"
- "enabled"
rule_infos:
- rule_type: Complete
definitions:
- [2]
rule_tree:
data:
services:
api:
enabled: 0
instruction_params:
virtual_data_document_lookup_params:
- dest: 3
path_components:
- literal_idx: 0
- literal_idx: 1
- literal_idx: 2
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 3 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "LoadTrue { dest: 1 }"
- "RuleReturn {}"
want_result: true
- note: virtual_lookup_rule_subobject
description: Lookup merges nested rule tree subobjects
data:
tenants:
alpha:
feature: "beta"
literals:
- "tenants"
- "alpha"
- "feature"
rule_infos:
- rule_type: Complete
definitions:
- [2]
rule_tree:
data:
tenants:
alpha:
extra: 0
instruction_params:
virtual_data_document_lookup_params:
- dest: 4
path_components:
- literal_idx: 0
- literal_idx: 1
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 4 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 2 }"
- "RuleReturn {}"
want_result:
feature: "beta"
extra: "feature"
- note: virtual_lookup_invalid_rule_index
description: Invalid rule index produces corresponding error
literals:
- "services"
instruction_params:
virtual_data_document_lookup_params:
- dest: 1
path_components:
- literal_idx: 0
rule_tree:
data:
services: 99
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
want_error: "Rule index 99 out of bounds"
- note: virtual_lookup_rule_data_conflict
description: Rule completely replaces data at the same path
data:
config:
mode: "data_value"
literals:
- "config"
- "mode"
- "rule_value"
rule_infos:
- rule_type: Complete
definitions:
- [3]
rule_tree:
data:
config:
mode: 0
instruction_params:
virtual_data_document_lookup_params:
- dest: 3
path_components:
- literal_idx: 0
- literal_idx: 1
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 3 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 2 }"
- "RuleReturn {}"
want_result: "rule_value"
- note: virtual_lookup_deep_path_5_levels
description: Lookup with 5-level deep path
data:
level1:
level2:
level3:
level4:
level5: "deep_value"
literals:
- "level1"
- "level2"
- "level3"
- "level4"
- "level5"
instruction_params:
virtual_data_document_lookup_params:
- dest: 5
path_components:
- literal_idx: 0
- literal_idx: 1
- literal_idx: 2
- literal_idx: 3
- literal_idx: 4
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 5 }"
want_result: "deep_value"
- note: virtual_lookup_deep_path_with_array_indices
description: Lookup path with array index components
data:
containers:
- name: "first"
- name: "second"
- name: "third"
literals:
- "containers"
- 1
- "name"
instruction_params:
virtual_data_document_lookup_params:
- dest: 3
path_components:
- literal_idx: 0
- literal_idx: 1
- literal_idx: 2
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 3 }"
want_result: "second"
- note: virtual_lookup_mixed_data_rules_deep
description: Deep lookup with rules at multiple levels
data:
org:
dept:
team:
lead: "data_lead"
literals:
- "org"
- "dept"
- "team"
- "lead"
- "rule_lead"
rule_infos:
- rule_type: Complete
definitions:
- [3]
rule_tree:
data:
org:
dept:
team:
lead: 0
instruction_params:
virtual_data_document_lookup_params:
- dest: 5
path_components:
- literal_idx: 0
- literal_idx: 1
- literal_idx: 2
- literal_idx: 3
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 5 }"
- "RuleInit { result_reg: 1, rule_index: 0 }"
- "Load { dest: 1, literal_idx: 4 }"
- "RuleReturn {}"
want_result: "rule_lead"
- note: virtual_lookup_nonexistent_deep_path
description: Lookup of non-existent deep path returns undefined
data:
root:
child: "value"
literals:
- "root"
- "nonexistent"
- "path"
instruction_params:
virtual_data_document_lookup_params:
- dest: 3
path_components:
- literal_idx: 0
- literal_idx: 1
- literal_idx: 2
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 3 }"
want_result: "#undefined"
- note: virtual_lookup_partial_match_deep_path
description: Partial path match returns undefined (not intermediate object)
data:
a:
b:
c: "value"
literals:
- "a"
- "b"
- "d"
instruction_params:
virtual_data_document_lookup_params:
- dest: 3
path_components:
- literal_idx: 0
- literal_idx: 1
- literal_idx: 2
instructions:
- "VirtualDataDocumentLookup { params_index: 0 }"
- "Return { value: 3 }"
want_result: "#undefined"