/*
 * Copyright (C) 2013, 2014 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#define LIBVIRT_VIRDBUSPRIV_H_ALLOW
#include "virdbuspriv.h"
#include "virlog.h"
#include "testutils.h"

VIR_LOG_INIT("tests.dbustest");

#define VERIFY(typname, valorig, valnew, fmt) \
    do { \
        VIR_DEBUG("Compare " typname " '" fmt "' to '" \
                  fmt "'", valorig, valnew); \
        if (valorig != valnew) { \
            fprintf(stderr, "Failed to round-trip " typname " '" \
                    fmt "' to '" fmt "'\n", valorig, valnew); \
            goto cleanup; \
        } \
    } while (0)

#define VERIFY_STR(typname, valorig, valnew, fmt) \
    do { \
        VIR_DEBUG("Compare " typname " '" fmt "' to '" \
                  fmt "'", valorig, valnew); \
        if (STRNEQ(valorig, valnew)) { \
            fprintf(stderr, "Failed to round-trip " typname " '" \
                    fmt "' to '" fmt "'\n", valorig, valnew); \
            goto cleanup; \
        } \
    } while (0)

static int testMessageSimple(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    unsigned char in_byte = 200, out_byte = 0;
    bool in_bool = true, out_bool = false;
    short in_int16 = 0xfefe, out_int16 = 0;
    unsigned short in_uint16 = 32000, out_uint16 = 0;
    int in_int32 = 100000000, out_int32 = 0;
    unsigned int in_uint32 = 200000000, out_uint32 = 0;
    long long in_int64 = 1000000000000LL, out_int64 = 0;
    unsigned long long in_uint64 = 2000000000000LL, out_uint64 = 0;
    double in_double = 3.14159265359, out_double = 0;
    const char *in_string = "Hello World";
    char *out_string = NULL;
    const char *in_objectpath = "/org/libvirt/test";
    char *out_objectpath = NULL;
    const char *in_signature = "ybnqiuxtdsog";
    char *out_signature = NULL;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "ybnqiuxtdsog",
                             in_byte, in_bool,
                             in_int16, in_uint16,
                             in_int32, in_uint32,
                             in_int64, in_uint64,
                             in_double, in_string,
                             in_objectpath, in_signature) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "ybnqiuxtdsog",
                             &out_byte, &out_bool,
                             &out_int16, &out_uint16,
                             &out_int32, &out_uint32,
                             &out_int64, &out_uint64,
                             &out_double, &out_string,
                             &out_objectpath, &out_signature) < 0) {
        VIR_DEBUG("Failed to decode arguments");
        goto cleanup;
    }

    VERIFY("byte", in_byte, out_byte, "%d");
    VERIFY("bool", in_bool, out_bool, "%d");
    VERIFY("int16", in_int16, out_int16, "%d");
    VERIFY("uint16", in_int16, out_int16, "%d");
    VERIFY("int32", in_int32, out_int32, "%d");
    VERIFY("uint32", in_int32, out_int32, "%d");
    VERIFY("int64", in_int64, out_int64, "%lld");
    VERIFY("uint64", in_int64, out_int64, "%lld");
    VERIFY("double", in_double, out_double, "%lf");
    VERIFY_STR("string", in_string, out_string, "%s");
    VERIFY_STR("objectpath", in_objectpath, out_objectpath, "%s");
    VERIFY_STR("signature", in_signature, out_signature, "%s");

    ret = 0;

 cleanup:
    VIR_FREE(out_string);
    VIR_FREE(out_signature);
    VIR_FREE(out_objectpath);
    virDBusMessageUnref(msg);
    return ret;
}


static int testMessageVariant(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    const char *in_str1 = "Hello";
    int in_int32 = 100000000, out_int32 = 0;
    const char *in_str2 = "World";
    char *out_str1 = NULL, *out_str2 = NULL;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "svs",
                             in_str1,
                             "i", in_int32,
                             in_str2) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "svs",
                             &out_str1,
                             "i", &out_int32,
                             &out_str2) < 0) {
        VIR_DEBUG("Failed to decode arguments");
        goto cleanup;
    }


    VERIFY_STR("str1", in_str1, out_str1, "%s");
    VERIFY("int32", in_int32, out_int32, "%d");
    VERIFY_STR("str2", in_str2, out_str2, "%s");

    ret = 0;

 cleanup:
    VIR_FREE(out_str1);
    VIR_FREE(out_str2);
    virDBusMessageUnref(msg);
    return ret;
}

static int testMessageArray(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    const char *in_str1 = "Hello";
    int in_int32a = 1000000000, out_int32a = 0;
    int in_int32b = 2000000000, out_int32b = 0;
    int in_int32c = -2000000000, out_int32c = 0;
    bool in_bool[] = { true, false, true }, out_bool[] = { false, true, false};
    const char *in_str2 = "World";
    char *out_str1 = NULL, *out_str2 = NULL;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "saiabs",
                             in_str1,
                             3, in_int32a, in_int32b, in_int32c,
                             3, in_bool[0], in_bool[1], in_bool[2],
                             in_str2) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "saiabs",
                             &out_str1,
                             3, &out_int32a, &out_int32b, &out_int32c,
                             3, &out_bool[0], &out_bool[1], &out_bool[2],
                             &out_str2) < 0) {
        VIR_DEBUG("Failed to decode arguments");
        goto cleanup;
    }


    VERIFY_STR("str1", in_str1, out_str1, "%s");
    VERIFY("int32a", in_int32a, out_int32a, "%d");
    VERIFY("int32b", in_int32b, out_int32b, "%d");
    VERIFY("int32c", in_int32c, out_int32c, "%d");
    VERIFY("bool[0]", in_bool[0], out_bool[0], "%d");
    VERIFY("bool[1]", in_bool[1], out_bool[1], "%d");
    VERIFY("bool[2]", in_bool[2], out_bool[2], "%d");
    VERIFY_STR("str2", in_str2, out_str2, "%s");

    ret = 0;

 cleanup:
    VIR_FREE(out_str1);
    VIR_FREE(out_str2);
    virDBusMessageUnref(msg);
    return ret;
}

static int testMessageEmptyArrayRef(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    const char *in_strv1[] = {};
    size_t out_nstrv1;
    char **out_strv1 = NULL;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "a&s",
                             0, in_strv1) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "a&s",
                             &out_nstrv1, &out_strv1) < 0) {
        VIR_DEBUG("Failed to decode arguments");
        goto cleanup;
    }


    if (out_nstrv1 != 0) {
        fprintf(stderr, "Expected 0 string, but got %zu\n",
                out_nstrv1);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    virDBusMessageUnref(msg);
    return ret;
}

static int testMessageSingleArrayRef(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    const char *in_strv1[] = {
        "Fishfood",
    };
    char **out_strv1 = NULL;
    size_t out_nstrv1 = 0;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "a&s",
                             1, in_strv1) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "a&s",
                             &out_nstrv1, &out_strv1) < 0) {
        VIR_DEBUG("Failed to decode arguments");
        goto cleanup;
    }


    if (out_nstrv1 != 1) {
        fprintf(stderr, "Expected 1 string, but got %zu\n",
                out_nstrv1);
        goto cleanup;
    }
    VERIFY_STR("strv1[0]", in_strv1[0], out_strv1[0], "%s");

    ret = 0;

 cleanup:
    if (out_strv1)
        VIR_FREE(out_strv1[0]);
    VIR_FREE(out_strv1);
    virDBusMessageUnref(msg);
    return ret;
}

static int testMessageArrayRef(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    const char *in_str1 = "Hello";
    int in_int32[] = {
        100000000, 2000000000, -2000000000
    };
    bool in_bool[] = { true, false, true };
    const char *in_strv1[] = {
        "Fishfood",
    };
    const char *in_strv2[] = {
        "Hello", "World",
    };
    int *out_int32 = NULL;
    size_t out_nint32 = 0;
    bool *out_bool = NULL;
    size_t out_nbool = 0;
    char **out_strv1 = NULL;
    char **out_strv2 = NULL;
    size_t out_nstrv1 = 0;
    size_t out_nstrv2 = 0;
    const char *in_str2 = "World";
    char *out_str1 = NULL, *out_str2 = NULL;
    size_t i;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "sa&sa&ia&ba&ss",
                             in_str1,
                             1, in_strv1,
                             3, in_int32,
                             3, in_bool,
                             2, in_strv2,
                             in_str2) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "sa&sa&ia&ba&ss",
                             &out_str1,
                             &out_nstrv1, &out_strv1,
                             &out_nint32, &out_int32,
                             &out_nbool, &out_bool,
                             &out_nstrv2, &out_strv2,
                             &out_str2) < 0) {
        VIR_DEBUG("Failed to decode arguments");
        goto cleanup;
    }


    VERIFY_STR("str1", in_str1, out_str1, "%s");
    if (out_nstrv1 != 1) {
        fprintf(stderr, "Expected 1 string, but got %zu\n",
                out_nstrv1);
        goto cleanup;
    }
    VERIFY_STR("strv1[0]", in_strv1[0], out_strv1[0], "%s");

    if (out_nint32 != 3) {
        fprintf(stderr, "Expected 3 integers, but got %zu\n",
                out_nint32);
        goto cleanup;
    }
    VERIFY("int32a", in_int32[0], out_int32[0], "%d");
    VERIFY("int32b", in_int32[1], out_int32[1], "%d");
    VERIFY("int32c", in_int32[2], out_int32[2], "%d");

    if (out_nbool != 3) {
        fprintf(stderr, "Expected 3 bools, but got %zu\n",
                out_nbool);
        goto cleanup;
    }
    VERIFY("bool[0]", in_bool[0], out_bool[0], "%d");
    VERIFY("bool[1]", in_bool[1], out_bool[1], "%d");
    VERIFY("bool[2]", in_bool[2], out_bool[2], "%d");

    if (out_nstrv2 != 2) {
        fprintf(stderr, "Expected 2 strings, but got %zu\n",
                out_nstrv2);
        goto cleanup;
    }
    VERIFY_STR("strv2[0]", in_strv2[0], out_strv2[0], "%s");
    VERIFY_STR("strv2[1]", in_strv2[1], out_strv2[1], "%s");

    VERIFY_STR("str2", in_str2, out_str2, "%s");

    ret = 0;

 cleanup:
    VIR_FREE(out_int32);
    VIR_FREE(out_bool);
    VIR_FREE(out_str1);
    VIR_FREE(out_str2);
    for (i = 0; i < out_nstrv1; i++)
        VIR_FREE(out_strv1[i]);
    VIR_FREE(out_strv1);
    for (i = 0; i < out_nstrv2; i++)
        VIR_FREE(out_strv2[i]);
    VIR_FREE(out_strv2);
    virDBusMessageUnref(msg);
    return ret;
}

static int testMessageStruct(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    unsigned char in_byte = 200, out_byte = 0;
    bool in_bool = true, out_bool = false;
    short in_int16 = 12000, out_int16 = 0;
    unsigned short in_uint16 = 32000, out_uint16 = 0;
    int in_int32 = 100000000, out_int32 = 0;
    unsigned int in_uint32 = 200000000, out_uint32 = 0;
    long long in_int64 = -1000000000000LL, out_int64 = 0;
    unsigned long long in_uint64 = 2000000000000LL, out_uint64 = 0;
    double in_double = 3.14159265359, out_double = 0;
    const char *in_string = "Hello World";
    char *out_string = NULL;
    const char *in_objectpath = "/org/libvirt/test";
    char *out_objectpath = NULL;
    const char *in_signature = "ybnqiuxtdsog";
    char *out_signature = NULL;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "ybn(qiuxtds)og",
                             in_byte, in_bool,
                             in_int16, in_uint16,
                             in_int32, in_uint32,
                             in_int64, in_uint64,
                             in_double, in_string,
                             in_objectpath, in_signature) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "ybn(qiuxtds)og",
                             &out_byte, &out_bool,
                             &out_int16, &out_uint16,
                             &out_int32, &out_uint32,
                             &out_int64, &out_uint64,
                             &out_double, &out_string,
                             &out_objectpath, &out_signature) < 0) {
        VIR_DEBUG("Failed to decode arguments");
        goto cleanup;
    }

    VERIFY("byte", in_byte, out_byte, "%d");
    VERIFY("bool", in_bool, out_bool, "%d");
    VERIFY("int16", in_int16, out_int16, "%d");
    VERIFY("uint16", in_int16, out_int16, "%d");
    VERIFY("int32", in_int32, out_int32, "%d");
    VERIFY("uint32", in_int32, out_int32, "%d");
    VERIFY("int64", in_int64, out_int64, "%lld");
    VERIFY("uint64", in_int64, out_int64, "%lld");
    VERIFY("double", in_double, out_double, "%lf");
    VERIFY_STR("string", in_string, out_string, "%s");
    VERIFY_STR("objectpath", in_objectpath, out_objectpath, "%s");
    VERIFY_STR("signature", in_signature, out_signature, "%s");

    ret = 0;

 cleanup:
    VIR_FREE(out_string);
    VIR_FREE(out_signature);
    VIR_FREE(out_objectpath);
    virDBusMessageUnref(msg);
    return ret;
}


static int testMessageDict(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    const char *in_str1 = "Hello";
    int in_int32a = 100000000, out_int32a = 0;
    const char *in_key1 = "turnover";
    int in_int32b = 200000000, out_int32b = 0;
    const char *in_key2 = "revenue";
    int in_int32c = 300000000, out_int32c = 0;
    const char *in_key3 = "debt";
    const char *in_str2 = "World";
    char *out_str1 = NULL, *out_str2 = NULL;
    char *out_key1 = NULL, *out_key2 = NULL, *out_key3 = NULL;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "(sa{si}s)",
                             in_str1,
                             3,
                             in_key1, in_int32a,
                             in_key2, in_int32b,
                             in_key3, in_int32c,
                             in_str2) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "(sa{si}s)",
                             &out_str1,
                             3,
                             &out_key1, &out_int32a,
                             &out_key2, &out_int32b,
                             &out_key3, &out_int32c,
                             &out_str2) < 0) {
        VIR_DEBUG("Failed to decode arguments");
        goto cleanup;
    }


    VERIFY_STR("str1", in_str1, out_str1, "%s");
    VERIFY("int32a", in_int32a, out_int32a, "%d");
    VERIFY("int32b", in_int32b, out_int32b, "%d");
    VERIFY("int32c", in_int32c, out_int32c, "%d");
    VERIFY_STR("key1", in_key1, out_key1, "%s");
    VERIFY_STR("key1", in_key2, out_key2, "%s");
    VERIFY_STR("key1", in_key3, out_key3, "%s");
    VERIFY_STR("str2", in_str2, out_str2, "%s");

    ret = 0;

 cleanup:
    VIR_FREE(out_str1);
    VIR_FREE(out_str2);
    VIR_FREE(out_key1);
    VIR_FREE(out_key2);
    VIR_FREE(out_key3);
    virDBusMessageUnref(msg);
    return ret;
}

static int testMessageDictRef(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    const char *in_str1 = "Hello";
    const char *in_strv1[] = {
        "Fruit1", "Apple",
        "Fruit2", "Orange",
        "Fruit3", "Kiwi",
    };
    const char *in_str2 = "World";
    char *out_str1 = NULL;
    size_t out_nint32 = 0;
    char **out_strv1 = NULL;
    char *out_str2 = NULL;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "(sa&{ss}s)",
                             in_str1,
                             3, in_strv1,
                             in_str2) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "(sa&{ss}s)",
                             &out_str1,
                             &out_nint32,
                             &out_strv1,
                             &out_str2) < 0) {
        VIR_DEBUG("Failed to decode arguments: '%s'", virGetLastErrorMessage());
        goto cleanup;
    }


    VERIFY_STR("str1", in_str1, out_str1, "%s");
    VERIFY_STR("strv1[0]", in_strv1[0], out_strv1[0], "%s");
    VERIFY_STR("strv1[1]", in_strv1[1], out_strv1[1], "%s");
    VERIFY_STR("strv1[2]", in_strv1[2], out_strv1[2], "%s");
    VERIFY_STR("strv1[3]", in_strv1[3], out_strv1[3], "%s");
    VERIFY_STR("strv1[4]", in_strv1[4], out_strv1[4], "%s");
    VERIFY_STR("strv1[5]", in_strv1[5], out_strv1[5], "%s");
    VERIFY_STR("str2", in_str2, out_str2, "%s");

    ret = 0;

 cleanup:
    VIR_FREE(out_str1);
    VIR_FREE(out_str2);
    if (out_strv1) {
        VIR_FREE(out_strv1[0]);
        VIR_FREE(out_strv1[1]);
        VIR_FREE(out_strv1[2]);
        VIR_FREE(out_strv1[3]);
        VIR_FREE(out_strv1[4]);
        VIR_FREE(out_strv1[5]);
    }
    VIR_FREE(out_strv1);
    virDBusMessageUnref(msg);
    return ret;
}

static int testMessageEmptyDictRef(const void *args G_GNUC_UNUSED)
{
    DBusMessage *msg = NULL;
    int ret = -1;
    const char *in_strv1[] = {};
    size_t out_nint32 = 0;
    char **out_strv1 = NULL;

    if (!(msg = dbus_message_new_method_call("org.libvirt.test",
                                             "/org/libvirt/test",
                                             "org.libvirt.test.astrochicken",
                                             "cluck"))) {
        VIR_DEBUG("Failed to allocate method call");
        goto cleanup;
    }

    if (virDBusMessageEncode(msg,
                             "a&{ss}",
                             0, in_strv1) < 0) {
        VIR_DEBUG("Failed to encode arguments");
        goto cleanup;
    }

    if (virDBusMessageDecode(msg,
                             "a&{ss}",
                             &out_nint32,
                             &out_strv1) < 0) {
        VIR_DEBUG("Failed to decode arguments: '%s'", virGetLastErrorMessage());
        goto cleanup;
    }

    if (out_nint32 != 0) {
        fprintf(stderr, "Unexpected dict entries\n");
        goto cleanup;
    }

    ret = 0;

 cleanup:
    virDBusMessageUnref(msg);
    return ret;
}

static int
mymain(void)
{
    int ret = 0;

    if (virTestRun("Test message simple ", testMessageSimple, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message variant ", testMessageVariant, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message array ", testMessageArray, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message array empty ref ", testMessageEmptyArrayRef, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message array single ref ", testMessageSingleArrayRef, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message array ref ", testMessageArrayRef, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message struct ", testMessageStruct, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message dict ", testMessageDict, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message dict empty ref ", testMessageEmptyDictRef, NULL) < 0)
        ret = -1;
    if (virTestRun("Test message dict ref ", testMessageDictRef, NULL) < 0)
        ret = -1;
    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

VIR_TEST_MAIN(mymain)
