/* whoopsie
 * 
 * Copyright © 2011-2013 Canonical Ltd.
 * Author: Evan Dandrea <evan.dandrea@canonical.com>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#define _XOPEN_SOURCE
#define _GNU_SOURCE

#include <glib.h>
#include <glib-object.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#include "../src/identifier.h"

static void
test_hex_to_char (void)
{
    char buf[9];
    whoopsie_hex_to_char (buf, "\xFF\xFF\xFF\xFF", 4);
    g_assert_cmpstr (buf, ==, "ffffffff");

}

static void
test_get_mac_address (void)
{
    char* res = NULL;
    GError* error = NULL;
    int fp = 0;
    char buf[18];
    GDir *net_dir;
    const gchar *device;
    gchar *path;
    gboolean found = FALSE;

    whoopsie_identifier_get_mac_address (&res, &error);
    g_assert (res != NULL);
    g_assert (error == NULL);

    /* ensure the MAC address matches any of the system's interfaces */
    net_dir = g_dir_open ("/sys/class/net", 0, NULL);
    if (net_dir == NULL) {
        g_print ("Could not open /sys/class/net\n");
        g_test_fail ();
        goto out;
    }

    while ((device = g_dir_read_name (net_dir)) != NULL) {
        /* ignore loopback device */
        if (strcmp (device, "lo") == 0)
            continue;

        path = g_build_filename ("/sys/class/net", device, "address", NULL);
        fp = open (path, O_RDONLY);
        g_free (path);

        if (fp < 0) {
            g_print ("Could not open /sys/class/net/%s/address\n", device);
            g_test_fail ();
            goto out;
        }
        if (read (fp, buf, 17) < 17) {
            g_print ("Could not read /sys/class/net/%s/address\n", device);
            g_test_fail ();
            goto out;
        }
        buf[17] = '\0';

        if (g_strcmp0 (buf, res) == 0) {
            found = TRUE;
            break;
        }
    }

    if (!found) {
        g_print ("MAC address does not match any value in /sys/class/net/*/address\n");
        g_test_fail ();
    }
out:
    if (net_dir != NULL)
        g_dir_close (net_dir);
    if (fp >= 0)
        close (fp);
    
    g_free (res);
}
static void
test_get_system_uuid (void)
{
    /* DEADBEEF-1234-1234-1234-DEADBEEF1234 */
    char* res = NULL;
    whoopsie_identifier_get_system_uuid (&res, NULL);
    if (getuid () != 0) {
        g_print ("Need root to run this complete test: ");
        goto out;
    }

    if (res == NULL) {
        g_test_fail ();
        goto out;
    }

    if (strlen (res) != 36) {
        g_test_fail ();
        goto out;
    }

    if ((res[8] != '-' || res[13] != '-') ||
        (res[18] != '-' || res[23] != '-')) {
        g_test_fail ();
        goto out;
    }

out:
    if (res)
        g_free (res);
    return;
}

static void
test_sha512 (void)
{
    char res[HASHLEN + 1] = {0};
    // "foo" -> sha512
    const char* expected = "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382"
                           "d624741d0dc6638326e282c41be5e4254d8820772c5518a"
                           "2c5a8c0c7f7eda19594a7eb539453e1ed7";
    whoopsie_identifier_sha512 ("foo", res, NULL);
    if (strcmp (res, expected) != 0)
        g_test_fail ();
}

static void
test_identifier_generate (void)
{
    char* result = NULL;
    char* expected = NULL;
    char hashed[HASHLEN + 1];

    whoopsie_identifier_generate (&result, NULL);
    if (getuid () != 0) {
        whoopsie_identifier_get_mac_address (&expected, NULL);
        if (!expected)
            whoopsie_identifier_get_system_uuid (&expected, NULL);
    } else {
        whoopsie_identifier_get_system_uuid (&expected, NULL);
    }
    whoopsie_identifier_sha512 (expected, hashed, NULL);
    if (strcmp (result, hashed) != 0)
        g_test_fail ();

    g_free (result);
    g_free (expected);
}
int
main (int argc, char** argv)
{
#if GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION < 35
    /* Deprecated in glib 2.35/2.36. */
    g_type_init ();
#endif
    g_test_init (&argc, &argv, NULL);

    /* This wont work when running under fakeroot. */
    if (!g_getenv ("FAKEROOTKEY"))
        g_test_add_func ("/whoopsie/get-system-uuid", test_get_system_uuid);
    g_test_add_func ("/whoopsie/hex-to-char", test_hex_to_char);
    g_test_add_func ("/whoopsie/get-mac-address", test_get_mac_address);
    g_test_add_func ("/whoopsie/sha512", test_sha512);
    g_test_add_func ("/whoopsie/identifier-generate", test_identifier_generate);

    /* Do not consider warnings to be fatal. */
    g_log_set_always_fatal (G_LOG_FATAL_MASK);

	return g_test_run ();
}
