# frozen_string_literal: true
# Copyright (c) 2010-2017 VMware, Inc.  All Rights Reserved.
# SPDX-License-Identifier: MIT

require 'test_helper'

class DeserializationTest < Test::Unit::TestCase
  def setup
    conn = VIM.new(ns: 'urn:vim25', rev: '4.0')
    @deserializer = RbVmomi::Deserializer.new conn
  end

  def check str, expected, type
    got = @deserializer.deserialize Nokogiri(str).root, type
    assert_equal expected, got
  end

  def test_moref
    check <<~EOS, VIM.Folder(nil, 'ha-folder-root'), 'Folder'
      <root type="Folder">ha-folder-root</root>
    EOS

    check <<~EOS, VIM.Datacenter(nil, 'ha-datacenter'), 'ManagedObjectReference'
      <ManagedObjectReference type="Datacenter" xsi:type="ManagedObjectReference">ha-datacenter</ManagedObjectReference>
    EOS
  end

  def test_dataobject
    obj = VIM.DatastoreSummary(
      capacity: 1000,
      accessible: true,
      datastore: VIM.Datastore(nil, 'foo'),
      freeSpace: 31,
      multipleHostAccess: false,
      name: 'baz',
      type: 'VMFS',
      url: 'http://foo/'
    )

    check <<~EOS, obj, 'DatastoreSummary'
      <root>
        <datastore type="Datastore">foo</datastore>
        <name>baz</name>
        <url>http://foo/</url>
        <capacity>1000</capacity>
        <freeSpace>31</freeSpace>
        <accessible>1</accessible>
        <multipleHostAccess>false</multipleHostAccess>
        <type>VMFS</type>
      </root>
    EOS
  end

  def test_enum
    check <<~EOS, 'add', 'ConfigSpecOperation'
      <root>add</root>
    EOS
  end

  def test_array
    obj = VIM.ObjectContent(
      obj: VIM.Folder(nil, 'ha-folder-root'),
      missingSet: [],
      propSet: [
        VIM.DynamicProperty(
          name: 'childEntity',
          val: [
            VIM.Datacenter(nil, 'ha-datacenter')
          ]
        )
      ]
    )

    check <<~EOS, obj, 'ObjectContent'
      <root xmlns:xsi="#{VIM::NS_XSI}">
         <obj type="Folder">ha-folder-root</obj>
         <propSet>
            <name>childEntity</name>
            <val xsi:type="ArrayOfManagedObjectReference">
               <ManagedObjectReference type="Datacenter" xsi:type="ManagedObjectReference">ha-datacenter</ManagedObjectReference>
            </val>
         </propSet>
      </root>
    EOS
  end

  def test_array2
    obj = VIM.DVPortStatus(
      linkUp: true,
      blocked: false,
      vlanIds: [
        VIM::NumericRange(start: 5, end: 7),
        VIM::NumericRange(start: 10, end: 20),
      ],
      vmDirectPathGen2InactiveReasonNetwork: [],
      vmDirectPathGen2InactiveReasonOther: []
    )

    check <<~EOS, obj, 'DVPortStatus'
      <root>
        <linkUp>1</linkUp>
        <blocked>false</blocked>
        <vlanIds>
          <start>5</start>
          <end>7</end>
        </vlanIds>
        <vlanIds>
          <start>10</start>
          <end>20</end>
        </vlanIds>
      </root>
    EOS
  end

  def test_empty_array
    obj = VIM.DVPortStatus(
      linkUp: true,
      blocked: false,
      vlanIds: [],
      vmDirectPathGen2InactiveReasonNetwork: [],
      vmDirectPathGen2InactiveReasonOther: []
    )

    check <<~EOS, obj, 'DVPortStatus'
      <root>
        <linkUp>1</linkUp>
        <blocked>false</blocked>
      </root>
    EOS
  end

  def test_fault
    obj = VIM.LocalizedMethodFault(
      localizedMessage: 'The attempted operation cannot be performed in the current state (Powered off).',
      fault: VIM.InvalidPowerState(
        requestedState: 'poweredOn',
        existingState: 'poweredOff',
        faultMessage: []
      )
    )

    check <<~EOS, obj, 'LocalizedMethodFault'
      <error xmlns:xsi="#{VIM::NS_XSI}">
        <fault xsi:type="InvalidPowerState">
          <requestedState>poweredOn</requestedState>
          <existingState>poweredOff</existingState>
        </fault>
        <localizedMessage>The attempted operation cannot be performed in the current state (Powered off).</localizedMessage>
      </error>
    EOS
  end

  def test_wait_for_updates
    obj = VIM.UpdateSet(
      version: '7',
      filterSet: [
        VIM.PropertyFilterUpdate(
          filter: VIM.PropertyFilter(nil, 'session[528BA5EB-335B-4AF6-B49C-6160CF5E8D5B]71E3AC7E-7927-4D9E-8BC3-522769F22DAF'),
          missingSet: [],
          objectSet: [
            VIM.ObjectUpdate(
              kind: 'enter',
              obj: VIM.VirtualMachine(nil, 'vm-1106'),
              missingSet: [],
              changeSet: [
                VIM.PropertyChange(
                  name: 'runtime.powerState',
                  op: 'assign',
                  val: 'poweredOn'
                )
              ]
            )
          ]
        )
      ]
    )

    check <<~EOS, obj, 'UpdateSet'
      <returnval xmlns:xsi="#{VIM::NS_XSI}">
        <version>7</version>
        <filterSet>
          <filter type="PropertyFilter">session[528BA5EB-335B-4AF6-B49C-6160CF5E8D5B]71E3AC7E-7927-4D9E-8BC3-522769F22DAF</filter>
          <objectSet>
            <kind>enter</kind>
            <obj type="VirtualMachine">vm-1106</obj>
            <changeSet>
              <name>runtime.powerState</name>
              <op>assign</op>
              <val xsi:type="VirtualMachinePowerState">poweredOn</val>
            </changeSet>
          </objectSet>
        </filterSet>
      </returnval>
    EOS
  end

  def test_binary
    obj = "\x00foo\x01bar\x02baz"
    check <<~EOS, obj, 'xsd:base64Binary'
      <root>AGZvbwFiYXICYmF6</root>
    EOS
  end

  def test_hba
    obj = VIM::HostBlockHba(
      key: 'key-vim.host.BlockHba-vmhba0',
      device: 'vmhba0',
      bus: 0,
      status: 'unknown',
      model: 'Virtual Machine Chipset',
      driver: 'ata_piix',
      pci: '00:07.1')

    check <<~EOS, obj, 'HostBlockHba'
      <hostBusAdapter xsi:type="HostBlockHba">
        <key>key-vim.host.BlockHba-vmhba0</key>
        <device>vmhba0</device>
        <bus>0</bus>
        <status>unknown</status>
        <model>Virtual Machine Chipset</model>
        <driver>ata_piix</driver>
        <pci>00:07.1</pci>
      </hostBusAdapter>
    EOS
  end

=begin
  def test_runtime_state
    obj = VIM::VirtualMachineDeviceRuntimeInfoVirtualEthernetCardRuntimeState(
      vmDirectPathGen2:Active => false,
      vmDirectPathGen2:InactiveReasonOther => ["vmNptIncompatibleHost"],
      vmDirectPathGen2:InactiveReasonVm => []
    )
    check <<-EOS, obj, 'VirtualMachineDeviceRuntimeInfoDeviceRuntimeState'
<runtimeState xsi:type="VirtualMachineDeviceRuntimeInfoVirtualEthernetCardRuntimeState" xmlns:xsi="#{VIM::NS_XSI}">
  <vmDirectPathGen2Active>false</vmDirectPathGen2Active>
  <vmDirectPathGen2InactiveReasonOther>vmNptIncompatibleHost</vmDirectPathGen2InactiveReasonOther>
</runtimeState>
    EOS
  end
=end

  def test_runtime_info
    obj = VIM::VirtualMachineRuntimeInfo(
      bootTime: Time.parse('2010-08-20 05:44:35 UTC'),
      connectionState: 'connected',
      faultToleranceState: 'notConfigured',
      featureMask: [],
      featureRequirement: [],
      host: VIM::HostSystem(nil, 'host-32'),
      maxCpuUsage: 5612,
      maxMemoryUsage: 3072,
      memoryOverhead: 128671744,
      numMksConnections: 1,
      offlineFeatureRequirement: [],
      powerState: 'poweredOn',
      recordReplayState: 'inactive',
      suspendInterval: 0,
      toolsInstallerMounted: false,
      device: []
    )

    check <<~EOS, obj, 'VirtualMachineRuntimeInfo'
      <val xsi:type="VirtualMachineRuntimeInfo" xmlns:xsi="#{VIM::NS_XSI}">
        <host type="HostSystem">host-32</host>
        <connectionState>connected</connectionState>
        <powerState>poweredOn</powerState>
        <faultToleranceState>notConfigured</faultToleranceState>
        <toolsInstallerMounted>false</toolsInstallerMounted>
        <bootTime>2010-08-20T05:44:35.0Z</bootTime>
        <suspendInterval>0</suspendInterval>
        <memoryOverhead>128671744</memoryOverhead>
        <maxCpuUsage>5612</maxCpuUsage>
        <maxMemoryUsage>3072</maxMemoryUsage>
        <numMksConnections>1</numMksConnections>
        <recordReplayState>inactive</recordReplayState>
      </val>
    EOS
  end

  def test_keyvalue
    obj = ['a', 'b']
    check <<~EOS, obj, 'KeyValue'
      <root>
        <key>a</key>
        <value>b</value>
      </root>
    EOS
  end

  def test_boolean
    check '<root>1</root>', true, 'xsd:boolean'
    check '<root>true</root>', true, 'xsd:boolean'
    check '<root>0</root>', false, 'xsd:boolean'
    check '<root>false</root>', false, 'xsd:boolean'
  end

  def test_int
    check '<root>5</root>', 5, 'xsd:byte'
    check '<root>5</root>', 5, 'xsd:short'
    check '<root>5</root>', 5, 'xsd:int'
    check '<root>5</root>', 5, 'xsd:long'
  end

  def test_float
    obj = 1.2
    check <<~EOS, obj, 'xsd:float'
      <root>1.2</root>
    EOS
  end

  def test_date
    time_str = '2010-08-20T05:44:35.0Z'
    obj = Time.parse(time_str)
    check <<~EOS, obj, 'xsd:dateTime'
      <root>#{time_str}</root>
    EOS
  end

  def test_array_mangling
    obj = ['foo']
    check <<~EOS, obj, 'ArrayOfString'
      <root><e>foo</e></root>
    EOS

    time_str = '2010-08-20T05:44:35.0Z'
    obj = [Time.parse(time_str)]
    check <<~EOS, obj, 'ArrayOfDateTime'
      <root><e>#{time_str}</e></root>
    EOS

    obj = [1]
    check <<~EOS, obj, 'ArrayOfAnyType'
      <root xmlns:xsi="#{VIM::NS_XSI}">
        <e xsi:type="xsd:int">1</e>
      </root>
    EOS
  end

  def test_propertypath
    check '<root>foo</root>', 'foo', 'PropertyPath'
  end

  def test_methodname
    check '<root>foo</root>', 'foo', 'MethodName'
  end

  def test_typename
    check '<root>foo</root>', 'foo', 'TypeName'
  end

  def test_new_fields
    obj = VIM::HostBlockHba(
      key: 'key-vim.host.BlockHba-vmhba0',
      device: 'vmhba0',
      bus: 0,
      status: 'unknown',
      model: 'Virtual Machine Chipset',
      driver: 'ata_piix',
      pci: '00:07.1')

    check <<~EOS, obj, 'HostBlockHba'
      <hostBusAdapter xsi:type="HostBlockHba">
        <key>key-vim.host.BlockHba-vmhba0</key>
        <device>vmhba0</device>
        <bus>0</bus>
        <status>unknown</status>
        <foo>bar</foo>
        <model>Virtual Machine Chipset</model>
        <driver>ata_piix</driver>
        <pci>00:07.1</pci>
      </hostBusAdapter>
    EOS
  end
end
