# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

cases:
  - note: partial_object_variable_key_collects_all_bindings
    data: {}
    input:
      items:
        FOO: 1
        BAR: 2
        BAZ: 3
    modules:
      - |
        package test

        p[k] if {
          some k, _ in input.items
        }
    query: data.test.p
    want_result:
      BAR: true
      BAZ: true
      FOO: true

  - note: partial_object_explicit_value_collects_all_bindings
    data: {}
    input:
      items:
        FOO: 1
        BAR: 2
        BAZ: 3
    modules:
      - |
        package test

        p[k] := v if {
          some k, v in input.items
        }
    query: data.test.p
    want_result:
      BAR: 2
      BAZ: 3
      FOO: 1

  - note: partial_object_dynamic_expression_key_collects_all_bindings
    data: {}
    input:
      items:
        FOO: 1
        BAR: 2
        BAZ: 3
      aliases:
        FOO: alias-foo
        BAR: alias-bar
        BAZ: alias-baz
    modules:
      - |
        package test

        p[input.aliases[k]] := v if {
          some k, v in input.items
        }
    query: data.test.p
    want_result:
      alias-bar: 2
      alias-baz: 3
      alias-foo: 1

  - note: partial_object_undefined_key_skipped
    # TODO(#719): RVM incorrectly materializes undefined keys instead of
    # skipping iterations where the key is undefined.
    skip: true
    data: {}
    input:
      items:
        FOO: 1
        BAR: 2
      aliases:
        FOO: alias-foo
    modules:
      - |
        package test

        p[input.aliases[k]] := v if {
          some k, v in input.items
        }
    query: data.test.p
    want_result:
      alias-foo: 1

  - note: partial_object_duplicate_key_last_wins
    # TODO(#719): regorus silently overwrites conflicting keys instead of
    # erroring when the same key is produced with different values.
    skip: true
    data: {}
    input: {}
    modules:
      - |
        package test

        p[k] := v if {
          some k, v in {"a": 1}
        }

        p[k] := v if {
          some k, v in {"a": 2}
        }
    query: data.test.p
    want_error: "conflict"

  - note: partial_object_duplicate_key_same_value_ok
    data: {}
    input: {}
    modules:
      - |
        package test

        p[k] if {
          some k, _ in {"a": 1}
        }

        p[k] if {
          some k, _ in {"a": 2}
        }
    query: data.test.p
    want_result:
      a: true

  - note: partial_object_single_element_input
    data: {}
    input:
      items:
        ONLY: 1
    modules:
      - |
        package test

        p[k] if {
          some k, _ in input.items
        }
    query: data.test.p
    want_result:
      ONLY: true

  - note: partial_object_static_bracket_prefix_collects_all_bindings
    data: {}
    input:
      items:
        FOO: 1
        BAR: 2
        BAZ: 3
    modules:
      - |
        package test

        p["a"][k] := v if {
          some k, v in input.items
        }
    query: data.test.p.a
    want_result:
      BAR: 2
      BAZ: 3
      FOO: 1

  - note: partial_object_constant_key_unsupported_in_rvm
    data: {}
    input:
      enabled: true
    modules:
      - |
        package test

        p["fixed"] if {
          input.enabled
        }
    query: data.test.p.fixed
    want_error: "partial object rules with constant keys are not yet supported by the RVM compiler"
    allow_interpreter_success: true

  - note: partial_object_constant_key_explicit_value_unsupported_in_rvm
    data: {}
    input:
      enabled: true
    modules:
      - |
        package test

        p["fixed"] := 7 if {
          input.enabled
        }
    query: data.test.p.fixed
    want_error: "partial object rules with constant keys are not yet supported by the RVM compiler"
    allow_interpreter_success: true

  - note: partial_object_multiple_bodies_collects_all_bindings
    data: {}
    input:
      items:
        FOO: 1
        BAR: 2
        BAZ: 3
    modules:
      - |
        package test

        p[k] if {
          some k, _ in input.items
          k in {"FOO", "BAR"}
        }

        p[k] if {
          some k, _ in input.items
          k == "BAZ"
        }
    query: data.test.p
    want_result:
      BAR: true
      BAZ: true
      FOO: true

  - note: partial_set_contains_collects_all_bindings
    data: {}
    input:
      items:
        FOO: 1
        BAR: 2
        BAZ: 3
    modules:
      - |
        package test

        p contains k if {
          some k, _ in input.items
        }
    query: data.test.p
    want_result:
      set!: ["BAR", "BAZ", "FOO"]

  - note: issue_712_reproducer_v1_partial_object
    data: {}
    input:
      servers:
        FOO: 1
        BAR: 2
        BAZ: 3
    modules:
      - |
        package test
        import rego.v1

        violations[k] if {
          some k, _ in input.servers
        }
    query: data.test.violations
    want_result:
      BAR: true
      BAZ: true
      FOO: true

  - note: issue_712_reproducer_v1_contains_partial_set
    data: {}
    input:
      servers:
        FOO: 1
        BAR: 2
        BAZ: 3
    modules:
      - |
        package test
        import rego.v1

        violations contains k if {
          some k, _ in input.servers
        }
    query: data.test.violations
    want_result:
      set!: ["BAR", "BAZ", "FOO"]

  - note: partial_object_multilevel_key_unsupported_in_rvm
    data: {}
    input:
      nested:
        app:
          read: 1
          write: 2
        ops:
          deploy: 3
    modules:
      - |
        package test

        p[a][b] if {
          some a, obj in input.nested
          some b, _ in obj
        }

        main := p
    query: data.test.main
    want_error: "partial object rules with nested bracket keys are not yet supported by the RVM compiler"
    allow_interpreter_success: true

  - note: partial_object_multilevel_key_explicit_value_unsupported_in_rvm
    data: {}
    input:
      nested:
        app:
          read: 1
          write: 2
        ops:
          deploy: 3
    modules:
      - |
        package test

        p[a][b] := v if {
          some a, obj in input.nested
          some b, v in obj
        }

        main := p
    query: data.test.main
    want_error: "partial object rules with nested bracket keys are not yet supported by the RVM compiler"
    allow_interpreter_success: true

  - note: partial_object_hidden_dynamic_prefix_unsupported_in_rvm
    data: {}
    input:
      nested:
        app:
          q:
            read: 1
            write: 2
        ops:
          q:
            deploy: 3
    modules:
      - |
        package test

        p[a].q[b] if {
          some a, obj in input.nested
          some b, _ in obj.q
        }

        main := p
    query: data.test.main
    want_error: "partial object rules with nested bracket keys are not yet supported by the RVM compiler"
    allow_interpreter_success: true

  - note: partial_object_array_iteration_collects_all_bindings
    data: {}
    input:
      items: ["FOO", "BAR", "BAZ"]
    modules:
      - |
        package test

        p[v] if {
          some _, v in input.items
        }
    query: data.test.p
    want_result:
      BAR: true
      BAZ: true
      FOO: true

  - note: partial_object_empty_input_is_empty_object
    data: {}
    input:
      items: {}
    modules:
      - |
        package test

        p[k] if {
          some k, _ in input.items
        }
    query: data.test.p
    want_result: {}

  - note: partial_object_duplicate_paths_same_key_same_value_deduplicates
    data: {}
    input:
      pairs:
        - alias: shared
          value: 1
        - alias: alpha
          value: 10
        - alias: shared
          value: 1
    modules:
      - |
        package test

        p[entry.alias] := entry.value if {
          some entry in input.pairs
        }
    query: data.test.p
    want_result:
      alpha: 10
      shared: 1

  - note: partial_object_duplicate_paths_same_key_different_values_conflict
    # TODO(#719): regorus silently overwrites conflicting keys instead of
    # erroring when the same key is produced with different values.
    skip: true
    data: {}
    input:
      pairs:
        - alias: shared
          value: 1
        - alias: shared
          value: 2
    modules:
      - |
        package test

        p[entry.alias] := entry.value if {
          some entry in input.pairs
        }
    query: data.test.p
    want_error: "conflict"

  - note: partial_object_undefined_key_skips_iteration
    # TODO(#719): RVM incorrectly materializes undefined keys instead of
    # skipping iterations where the key is undefined.
    skip: true
    data: {}
    input:
      items:
        FOO: 1
        BAR: 2
        BAZ: 3
      aliases:
        FOO: alias-foo
        BAZ: alias-baz
    modules:
      - |
        package test

        p[input.aliases[k]] := v if {
          some k, v in input.items
        }
    query: data.test.p
    want_result:
      alias-baz: 3
      alias-foo: 1

  - note: partial_object_undefined_value_skips_iteration
    # TODO(#719): RVM incorrectly materializes undefined values instead of
    # skipping iterations where the value is undefined.
    skip: true
    data: {}
    input:
      keys: ["FOO", "BAR", "BAZ"]
      values:
        FOO: 1
        BAZ: 3
    modules:
      - |
        package test

        p[k] := input.values[k] if {
          some _, k in input.keys
        }
    query: data.test.p
    want_result:
      BAZ: 3
      FOO: 1

  - note: partial_object_mixed_undefined_key_value_cases_skip_bad_iterations
    # TODO(#719): RVM incorrectly materializes undefined keys/values instead of
    # skipping iterations where the key or value is undefined.
    skip: true
    data: {}
    input:
      rows:
        - src: keep
        - src: missing_alias
        - src: missing_value
        - src: missing_both
      aliases:
        keep: alias-keep
        missing_value: alias-no-value
      values:
        keep: 1
        missing_alias: 2
    modules:
      - |
        package test

        p[input.aliases[row.src]] := input.values[row.src] if {
          some row in input.rows
        }
    query: data.test.p
    want_result:
      alias-keep: 1

  - note: partial_object_and_partial_set_same_name_conflict
    data: {}
    input:
      items:
        FOO: 1
    modules:
      - |
        package test

        p[k] if {
          some k, _ in input.items
        }

        p contains "shadow" if {
          true
        }
    query: data.test.p
    want_error: "has multiple types"

  - note: partial_object_complete_rule_conflicts_with_partial_object
    data: {}
    input:
      items:
        a: 1
    modules:
      - |
        package test

        p := {"fixed": 1}

        p[k] := v if {
          some k, v in input.items
        }
    query: data.test.p
    want_error: "multiple types"

  - note: partial_object_partial_set_conflicts_with_partial_object
    data: {}
    input:
      items:
        a: 1
    modules:
      - |
        package test

        p contains k if {
          some k, _ in input.items
        }

        p[k] := 1 if {
          some k, _ in input.items
        }
    query: data.test.p
    want_error: "multiple types"

  - note: partial_object_large_range_counts_all_entries
    data: {}
    input: {}
    modules:
      - |
        package test

        p[key] := n if {
          n := numbers.range(0, 255)[_]
          key := sprintf("k-%d", [n])
        }

        main := count(p)
    query: data.test.main
    want_result: 256

  - note: partial_object_rbac_duplicate_actions_deduplicate
    data:
      role_permissions:
        reader: ["read", "list"]
        writer: ["read", "write"]
        auditor: ["read", "list"]
    input:
      user_roles: ["reader", "writer", "auditor"]
    modules:
      - |
        package test

        allowed_actions[action] if {
          some role in input.user_roles
          some action in data.role_permissions[role]
        }
    query: data.test.allowed_actions
    want_result:
      list: true
      read: true
      write: true

  - note: partial_object_violations_real_world_pattern
    data: {}
    input:
      spec:
        containers:
          - name: api
            securityContext:
              readOnlyRootFilesystem: false
          - name: worker
            securityContext:
              readOnlyRootFilesystem: true
          - name: sidecar
    modules:
      - |
        package test

        violations[msg] if {
          some container in input.spec.containers
          not container.securityContext.readOnlyRootFilesystem
          msg := sprintf("Container %s must use readOnlyRootFilesystem", [container.name])
        }
    query: data.test.violations
    want_result:
      Container api must use readOnlyRootFilesystem: true
      Container sidecar must use readOnlyRootFilesystem: true

  - note: partial_object_resource_mapping_filters_valid_resources
    data: {}
    input:
      resources:
        svc-api:
          cpu: 1
        job-cleanup:
          cpu: 2
        svc-worker:
          cpu: 4
    modules:
      - |
        package test

        valid_resource(name) if {
          startswith(name, "svc-")
        }

        resources[name] := config if {
          some name, config in input.resources
          valid_resource(name)
        }
    query: data.test.resources
    want_result:
      svc-api:
        cpu: 1
      svc-worker:
        cpu: 4

  - note: partial_object_computed_concat_key_constant_body
    data: {}
    modules:
      - |
        package test

        p[concat("", ["edge", "-", "key"])] if {
          true
        }
    query: data.test.p
    want_result:
      edge-key: true

  - note: partial_object_duplicate_computed_key_same_value_merges
    data: {}
    input:
      items:
        A: 0
        a: 0
    modules:
      - |
        package test

        p[lower(k)] := 1 if {
          some k, _ in input.items
        }
    query: data.test.p
    want_result:
      a: 1

  - note: partial_object_function_key_and_object_value
    data: {}
    input:
      items:
        a: 1
        b: 2
    modules:
      - |
        package test

        f(x) := concat(":", [x, "suffix"])

        p[f(k)] := {"nested": v + 1} if {
          some k, v in input.items
        }
    query: data.test.p
    want_result:
      "a:suffix":
        nested: 2
      "b:suffix":
        nested: 3

  - note: partial_object_array_index_key_uses_selected_elements
    data: {}
    input:
      keys: ["alpha", "beta"]
      values: [10, 20]
    modules:
      - |
        package test

        p[input.keys[i]] := v if {
          some i, v in input.values
        }
    query: data.test.p
    want_result:
      alpha: 10
      beta: 20

  - note: partial_object_computed_empty_and_special_string_keys
    data: {}
    modules:
      - |
        package test

        p[concat("", [""])] := "empty" if {
          true
        }

        p[concat("", ["a/b?c#d"])] := "special" if {
          true
        }
    query: data.test.p
    want_result:
      "": "empty"
      a/b?c#d: "special"

  - note: partial_object_not_filters_blocked_entries
    data: {}
    input:
      items:
        allowed: true
        blocked: true
      blocked:
        blocked: true
    modules:
      - |
        package test

        p[k] if {
          some k, _ in input.items
          not input.blocked[k]
        }
    query: data.test.p
    want_result:
      allowed: true

  - note: partial_object_dot_bracket_object_value_collects_all_bindings
    data: {}
    input:
      items:
        a: 1
        b: 2
    modules:
      - |
        package test

        p.config[k] := {"nested": v} if {
          some k, v in input.items
        }
    query: data.test.p.config
    want_result:
      a:
        nested: 1
      b:
        nested: 2

  - note: partial_object_dynamic_prefix_static_suffix_unsupported_in_rvm
    data: {}
    input:
      items:
        a: 1
        b: 2
    modules:
      - |
        package test

        p[k]["fixed"] := upper(k) if {
          some k, _ in input.items
        }

        main := p
    query: data.test.main
    want_error: "partial object rules with nested bracket keys are not yet supported by the RVM compiler"
    allow_interpreter_success: true

  - note: partial_object_literal_prefix_nested_unsupported_in_rvm
    data: {}
    input:
      items:
        a: 1
        b: 2
    modules:
      - |
        package test

        p[1][k] := v if {
          some k, v in input.items
        }

        main := p
    query: data.test.main
    want_error: "partial object rules with nested bracket keys are not yet supported by the RVM compiler"
    allow_interpreter_success: true

  - note: partial_object_three_level_nested_dynamic_unsupported_in_rvm
    data: {}
    input:
      nested:
        app:
          read: 1
          write: 2
        ops:
          deploy: 3
    modules:
      - |
        package test

        p["root"][a][b] := v if {
          some a, obj in input.nested
          some b, v in obj
        }

        main := p
    query: data.test.main
    want_error: "partial object rules with nested bracket keys are not yet supported by the RVM compiler"
    allow_interpreter_success: true

  - note: partial_object_with_body_unsupported_in_rvm
    data: {}
    input:
      enabled: false
      items:
        a: 1
    modules:
      - |
        package test

        gate if {
          input.enabled
        }

        p[k] := v if {
          some k, v in input.items
          data.test.gate with input as {"enabled": true}
        }
    query: data.test.p
    want_error: "the `with` keyword is not supported by the compiler yet"
    allow_interpreter_success: true

  - note: partial_object_every_vacuous_truth_collects_empty_arrays
    # TODO(#719): RVM currently includes the failing `bad` group here, while the
    # interpreter returns only `empty` and `ok` (expected per vacuous truth
    # semantics).
    skip: true
    data: {}
    input:
      groups:
        ok: [1, 2]
        bad: [1, 0]
        empty: []
    modules:
      - |
        package test

        p[k] if {
          some k, arr in input.groups
          every v in arr {
            v > 0
          }
        }
    query: data.test.p
    want_result:
      empty: true
      ok: true

  - note: partial_object_join_var_multiple_bindings
    data:
      a: ["1", "2", "3", "4"]
      g:
        a: ["1", "0", "0", "0"]
        b: ["0", "2", "0", "0"]
        c: ["0", "0", "0", "4"]
    modules:
      - |
        package test

        p[k] := v if {
          data.a[i] = v
          data.g[k][i] = v
        }
    query: data.test.p
    want_result:
      a: "1"
      b: "2"
      c: "4"

  - note: partial_object_composite_value
    data:
      g:
        a: [1, 0, 0, 0]
        b: [0, 2, 0, 0]
        c: [0, 0, 0, 4]
    modules:
      - |
        package test

        p[k] := [i, {"v2": v}] if {
          data.g[k] = x
          x[i] = v
          v != 0
        }
    query: data.test.p
    want_result:
      a: [0, {v2: 1}]
      b: [1, {v2: 2}]
      c: [3, {v2: 4}]

  - note: partial_object_true_semantics_dedupes_duplicate_keys
    data: {}
    modules:
      - |
        package test

        p[k] if {
          ks := ["a", "b", "c", "a"]
          ks[_] = k
        }
    query: data.test.p
    want_result:
      a: true
      b: true
      c: true
