# 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"
