/** Tries to validate conversion of device properties to {@code Map<String, String>} */
  @Test
  public void validateGetRawDeviceProperties() {
    Map<String, String> devProp;

    String customDevPropSpec =
        "{type=disk;prop={bootable=^(true|false)$}};"
            + "{type=interface;prop={speed=[0-9]{1,5};duplex=^(full|half)$}};";

    // mock DevicePropertiesUtils
    DevicePropertiesUtils utils = mockDevicePropertiesUtils(customDevPropSpec);

    // test if custom properties spec is valid
    assertTrue(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));

    // test parsed properties
    assertEquals(2, utils.getDeviceTypesWithProperties(Version.v3_3).size());

    // test disk properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.DISK);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(devProp, "bootable", "^(true|false)$");

    // test interface properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.INTERFACE);
    validatePropertyMap(devProp, 2);
    validatePropertyValue(devProp, "speed", "[0-9]{1,5}");
    validatePropertyValue(devProp, "duplex", "^(full|half)$");
  }
  /**
   * Tries to validate custom device properties specification with property value containing invalid
   * characters
   */
  @Test
  public void customDevPropSpecWithInvalidCharsPropertyValue() {
    String customDevPropSpec = "{type=disk;prop={bootable=([{};])?}}";
    DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();

    assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
  }
  /** Tries to validate custom device properties specification with invalid property key name */
  @Test
  public void customDevPropSpecWithInvalidPropertyKeyName() {
    String customDevPropSpec = "{type=disk;prop={boot*able=^(true|false)$}}";
    DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();

    assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
  }
  /** Tries to validate valid custom device properties specification with special characters */
  @Test
  public void validCustomDevPropSpecWithSpecChars() {
    String customDevPropSpec =
        "{type=disk;prop={bootable=[\\@\\#\\$\\%\\^\\&\\*\\(\\)\\{\\}\\:\\<\\>\\,\\.\\?\\[\\]]?}};";
    DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();

    assertTrue(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
  }
  /** Tries to validate valid custom device properties specification */
  @Test
  public void validCustomDevPropSpec() {
    String customDevPropSpec =
        "{type=disk;prop={bootable=^(true|false)$}};"
            + "{type=interface;prop={speed=[0-9]{1,5};duplex=^(full|half)$;debug=([a-z0-9A-Z]*)$}};"
            + "{type=video;prop={turned_on=^(true|false)$}};"
            + "{type=sound;prop={volume=[0-9]{1,2}}};"
            + "{type=controller;prop={hotplug=^(true|false)$}};"
            + "{type=balloon;prop={max_size=[0-9]{1,15}}};"
            + "{type=channel;prop={auth_type=^(plain|md5|kerberos)$}};"
            + "{type=redir;prop={max_len=[0-9]{1,15}}};"
            + "{type=console;prop={type=^(text|vnc)$}};"
            + "{type=smartcard;prop={version=([1-9]{1}).([0-9]{1})}}";
    DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();

    assertTrue(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
  }
  /**
   * Tries to validate if a valid custom device properties specification have been parsed correctly
   */
  @Test
  public void parseValidCustomDevPropSpec() {
    Map<String, String> devProp;

    String customDevPropSpec =
        "{type=disk;prop={bootable=^(true|false)$}};"
            + "{type=interface;prop={speed=[0-9]{1,5};duplex=^(full|half)$}};"
            + "{type=video;prop={turned_on=^(true|false)$}};"
            + "{type=sound;prop={volume=[0-9]{1,2}}};"
            + "{type=controller;prop={hotplug=^(true|false)$}};"
            + "{type=balloon;prop={max_size=[0-9]{1,15}}};"
            + "{type=channel;prop={auth_type=^(plain|md5|kerberos)$}};"
            + "{type=redir;prop={max_len=[0-9]{1,15}}};"
            + "{type=console;prop={type=^(text|vnc)$;prop=\\{\\}}};"
            + "{type=smartcard;prop={spec_chars=[\\@\\#\\$\\%\\^\\&\\*\\(\\)\\{\\}\\:\\<\\>\\,\\.\\?\\[\\]]?}}";

    // mock DevicePropertiesUtils
    DevicePropertiesUtils utils = mockDevicePropertiesUtils(customDevPropSpec);

    // test if custom properties spec is valid
    assertTrue(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));

    // test parsed properties
    assertEquals(10, utils.getDeviceTypesWithProperties(Version.v3_3).size());

    // test disk properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.DISK);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(devProp, "bootable", "^(true|false)$");

    // test interface properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.INTERFACE);
    validatePropertyMap(devProp, 2);
    validatePropertyValue(devProp, "speed", "[0-9]{1,5}");
    validatePropertyValue(devProp, "duplex", "^(full|half)$");

    // test video properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.VIDEO);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(devProp, "turned_on", "^(true|false)$");

    // test sound properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.SOUND);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(devProp, "volume", "[0-9]{1,2}");

    // test video properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.CONTROLLER);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(devProp, "hotplug", "^(true|false)$");

    // test balloon properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.BALLOON);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(devProp, "max_size", "[0-9]{1,15}");

    // test channel properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.CHANNEL);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(devProp, "auth_type", "^(plain|md5|kerberos)$");

    // test redir properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.REDIR);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(devProp, "max_len", "[0-9]{1,15}");

    // test console properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.CONSOLE);
    validatePropertyMap(devProp, 2);
    validatePropertyValue(devProp, "type", "^(text|vnc)$");
    validatePropertyValue(devProp, "prop", "\\{\\}");

    // test smartcard properties
    devProp = utils.getDeviceProperties(Version.v3_3, VmDeviceGeneralType.SMARTCARD);
    validatePropertyMap(devProp, 1);
    validatePropertyValue(
        devProp, "spec_chars", "[\\@\\#\\$\\%\\^\\&\\*\\(\\)\\{\\}\\:\\<\\>\\,\\.\\?\\[\\]]?");
  }