aliases_json: |
  [
    {
      "namespace": "Microsoft.Storage",
      "resourceTypes": [
        {
          "resourceType": "storageAccounts",
          "aliases": [
            {
              "name": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly",
              "defaultPath": "properties.supportsHttpsTrafficOnly",
              "paths": []
            },
            {
              "name": "Microsoft.Storage/storageAccounts/isHnsEnabled",
              "defaultPath": "properties.isHnsEnabled",
              "paths": []
            }
          ]
        }
      ]
    },
    {
      "namespace": "Microsoft.Network",
      "resourceTypes": [
        {
          "resourceType": "networkSecurityGroups",
          "aliases": [
            {
              "name": "Microsoft.Network/networkSecurityGroups/securityRules[*].protocol",
              "defaultPath": "properties.securityRules[*].properties.protocol",
              "paths": []
            },
            {
              "name": "Microsoft.Network/networkSecurityGroups/securityRules[*].access",
              "defaultPath": "properties.securityRules[*].properties.access",
              "paths": []
            },
            {
              "name": "Microsoft.Network/networkSecurityGroups/securityRules[*].name",
              "defaultPath": "properties.securityRules[*].name",
              "paths": []
            }
          ]
        }
      ]
    }
  ]

cases:
  - note: round-trip simple resource
    input:
      name: myStorage
      type: "Microsoft.Storage/storageAccounts"
      location: westus2
      sku:
        name: Standard_LRS
      properties:
        supportsHttpsTrafficOnly: true
        isHnsEnabled: false
    round_trip: true
    expected_round_trip:
      name: myStorage
      type: "Microsoft.Storage/storageAccounts"
      location: westus2
      sku:
        name: Standard_LRS
      properties:
        supportsHttpsTrafficOnly: true
        isHnsEnabled: false

  - note: round-trip sub-resource
    input:
      name: myNsg
      type: "Microsoft.Network/networkSecurityGroups"
      properties:
        securityRules:
          - name: rule1
            properties:
              protocol: Tcp
              access: Allow
    round_trip: true
    expected_round_trip:
      name: myNsg
      type: "Microsoft.Network/networkSecurityGroups"
      properties:
        securityRules:
          - name: rule1
            properties:
              protocol: Tcp
              access: Allow

  - note: round-trip versioned array alias (element field remap)
    aliases_json: |
      [
        {
          "namespace": "Microsoft.Network",
          "resourceTypes": [
            {
              "resourceType": "firewallPolicies",
              "aliases": [
                {
                  "name": "Microsoft.Network/firewallPolicies/rules[*].priority",
                  "defaultPath": "properties.rules[*].properties.priority",
                  "paths": [
                    {
                      "path": "properties.rules[*].properties.prio",
                      "apiVersions": ["2021-01-01"]
                    }
                  ]
                },
                {
                  "name": "Microsoft.Network/firewallPolicies/rules[*].name",
                  "defaultPath": "properties.rules[*].name",
                  "paths": []
                }
              ]
            }
          ]
        }
      ]
    input:
      name: myPolicy
      type: "Microsoft.Network/firewallPolicies"
      properties:
        rules:
          - name: rule1
            properties:
              prio: 100
    api_version: "2021-01-01"
    round_trip: true
    expected_round_trip:
      name: myPolicy
      type: "Microsoft.Network/firewallPolicies"
      properties:
        rules:
          - name: rule1
            properties:
              prio: 100

  # Regression: default and versioned paths both produce exactly one element
  # remap (same count), but the source field differs.  A length-only comparison
  # would silently reuse the default aggregate, producing incorrect results for
  # the versioned API version.
  - note: round-trip versioned remap with same count but different source field
    aliases_json: |
      [
        {
          "namespace": "Microsoft.Network",
          "resourceTypes": [
            {
              "resourceType": "firewallPolicies",
              "aliases": [
                {
                  "name": "Microsoft.Network/firewallPolicies/rules[*].priority",
                  "defaultPath": "properties.rules[*].properties.oldA",
                  "paths": [
                    {
                      "path": "properties.rules[*].properties.oldB",
                      "apiVersions": ["2023-06-01"]
                    }
                  ]
                },
                {
                  "name": "Microsoft.Network/firewallPolicies/rules[*].name",
                  "defaultPath": "properties.rules[*].name",
                  "paths": []
                }
              ]
            }
          ]
        }
      ]
    input:
      name: myPolicy
      type: "Microsoft.Network/firewallPolicies"
      properties:
        rules:
          - name: rule1
            properties:
              oldB: 100
    api_version: "2023-06-01"
    round_trip: true
    expected_round_trip:
      name: myPolicy
      type: "Microsoft.Network/firewallPolicies"
      properties:
        rules:
          - name: rule1
            properties:
              oldB: 100

  - note: round-trip systemData and extendedLocation
    input:
      name: myStorage
      type: "Microsoft.Storage/storageAccounts"
      location: westus2
      identity:
        type: SystemAssigned
        principalId: pid-123
        userAssignedIdentities:
          /subscriptions/Sub/resourceGroups/Rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/Uai1: {}
      systemData:
        createdBy: user@example.com
        createdByType: User
        createdAt: "2023-01-01T00:00:00Z"
      extendedLocation:
        name: edge-site-1
        type: EdgeZone
      properties:
        supportsHttpsTrafficOnly: true
    expected_normalized:
      name: myStorage
      type: "Microsoft.Storage/storageAccounts"
      location: westus2
      identity:
        type: SystemAssigned
        principalid: pid-123
        userassignedidentities:
          /subscriptions/Sub/resourceGroups/Rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/Uai1: {}
      systemdata:
        createdby: user@example.com
        createdbytype: User
        createdat: "2023-01-01T00:00:00Z"
      extendedlocation:
        name: edge-site-1
        type: EdgeZone
      supportshttpstrafficonly: true
    round_trip: true
    expected_round_trip:
      name: myStorage
      type: "Microsoft.Storage/storageAccounts"
      location: westus2
      identity:
        type: SystemAssigned
        principalId: pid-123
        userAssignedIdentities:
          /subscriptions/Sub/resourceGroups/Rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/Uai1: {}
      systemData:
        createdBy: user@example.com
        createdByType: User
        createdAt: "2023-01-01T00:00:00Z"
      extendedLocation:
        name: edge-site-1
        type: EdgeZone
      properties:
        supportsHttpsTrafficOnly: true

  # Regression: element remap must remove the stale ARM source field from the
  # normalized output.  Without cleanup, both the alias short name AND the
  # original ARM leaf key survive; casing restoration during denormalization
  # then produces a duplicate key (e.g. both "prio" and "priority").
  - note: element remap removes stale ARM source field
    aliases_json: |
      [
        {
          "namespace": "Microsoft.Network",
          "resourceTypes": [
            {
              "resourceType": "firewallPolicies",
              "aliases": [
                {
                  "name": "Microsoft.Network/firewallPolicies/rules[*].priority",
                  "defaultPath": "properties.rules[*].properties.prio",
                  "paths": []
                },
                {
                  "name": "Microsoft.Network/firewallPolicies/rules[*].name",
                  "defaultPath": "properties.rules[*].name",
                  "paths": []
                }
              ]
            }
          ]
        }
      ]
    input:
      name: myPolicy
      type: "Microsoft.Network/firewallPolicies"
      properties:
        rules:
          - name: rule1
            properties:
              prio: 42
    # Normalize: "prio" (ARM leaf) → "priority" (alias short name).
    # The stale "prio" key must be removed from the normalized element.
    expected_normalized:
      name: myPolicy
      type: "Microsoft.Network/firewallPolicies"
      rules:
        - name: rule1
          priority: 42
    # Round-trip: normalize → denormalize should restore ARM structure.
    round_trip: true
    expected_round_trip:
      name: myPolicy
      type: "Microsoft.Network/firewallPolicies"
      properties:
        rules:
          - name: rule1
            properties:
              prio: 42

  # Regression: same stale-field-cleanup scenario but with a dotted ARM leaf
  # path (e.g. "config.value" rather than a single segment "prio").
  # The remove_element_field helper must navigate to the parent object and
  # remove the leaf key via remove_at_dotted_path.
  - note: element remap removes stale dotted ARM source field
    aliases_json: |
      [
        {
          "namespace": "Microsoft.Test",
          "resourceTypes": [
            {
              "resourceType": "widgets",
              "aliases": [
                {
                  "name": "Microsoft.Test/widgets/items[*].rating",
                  "defaultPath": "properties.items[*].properties.config.score",
                  "paths": []
                },
                {
                  "name": "Microsoft.Test/widgets/items[*].name",
                  "defaultPath": "properties.items[*].name",
                  "paths": []
                }
              ]
            }
          ]
        }
      ]
    input:
      type: "Microsoft.Test/widgets"
      properties:
        items:
          - name: w1
            properties:
              config:
                score: 5
    # Normalize: "config.score" (dotted ARM leaf) → "rating" (alias short name).
    # The stale "config.score" path must be removed; only "rating" should remain.
    expected_normalized:
      type: "Microsoft.Test/widgets"
      items:
        - name: w1
          config: {}
          rating: 5
    # Round-trip: normalize → denormalize should restore ARM structure.
    round_trip: true
    expected_round_trip:
      type: "Microsoft.Test/widgets"
      properties:
        items:
          - name: w1
            properties:
              config:
                score: 5

  # Regression: array base rename must move (not clone) the value so that
  # the stale ARM base key does not survive in the normalized output.
  # Without the removal, denormalization produces a duplicate key.
  - note: array base rename removes stale ARM base key
    aliases_json: |
      [
        {
          "namespace": "Microsoft.Test",
          "resourceTypes": [
            {
              "resourceType": "widgets",
              "aliases": [
                {
                  "name": "Microsoft.Test/widgets/items[*].label",
                  "defaultPath": "properties.entries[*].label",
                  "paths": []
                }
              ]
            }
          ]
        }
      ]
    input:
      type: "Microsoft.Test/widgets"
      properties:
        entries:
          - label: hello
    # Normalize: ARM base "entries" → alias base "items".
    # The stale "entries" key must be removed; only "items" should remain.
    expected_normalized:
      type: "Microsoft.Test/widgets"
      items:
        - label: hello
    # Round-trip: normalize → denormalize should restore ARM structure.
    round_trip: true
    expected_round_trip:
      type: "Microsoft.Test/widgets"
      properties:
        entries:
          - label: hello

  # Regression: denormalize reverse element remap with a dotted ARM target
  # must preserve restored casing (e.g. "Config.Score") rather than
  # re-lowercasing it.
  - note: round-trip dotted element remap preserves ARM casing
    aliases_json: |
      [
        {
          "namespace": "Microsoft.Test",
          "resourceTypes": [
            {
              "resourceType": "widgets",
              "aliases": [
                {
                  "name": "Microsoft.Test/widgets/items[*].rating",
                  "defaultPath": "properties.items[*].properties.Config.Score",
                  "paths": []
                },
                {
                  "name": "Microsoft.Test/widgets/items[*].name",
                  "defaultPath": "properties.items[*].name",
                  "paths": []
                }
              ]
            }
          ]
        }
      ]
    input:
      type: "Microsoft.Test/widgets"
      properties:
        items:
          - name: w1
            properties:
              Config:
                Score: 9
    expected_normalized:
      type: "Microsoft.Test/widgets"
      items:
        - name: w1
          config: {}
          rating: 9
    round_trip: true
    expected_round_trip:
      type: "Microsoft.Test/widgets"
      properties:
        items:
          - name: w1
            properties:
              Config:
                Score: 9
