/* 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 500

#include <unistd.h>
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "../src/globals.h"
#include "../src/logging.h"

int foreground;

void
test_logging (void)
{
    char template[] = "/tmp/XXXXXX";

    char buf[512] = {0};
    FILE* fp = NULL;
    const char *expected = "Hello.\n";

    foreground = 1;

    int fd;
    fpos_t pos;

    /* http://c-faq.com/stdio/undofreopen.html */
    fflush (stdout);
    fgetpos (stdout, &pos);
    fd = dup (fileno (stdout));

    tmpnam (template);
    if (freopen (template, "w", stdout) == NULL) {
        g_printerr ("Could not open temporary stdout (%d).\n", errno);
        g_test_fail ();
        goto out;
    }

    /* Test opening, writing to, and closing the log. */
    open_log ();
    log_msg ("Hello.\n");
    close_log ();

    /* Did we write a log file? */
    if (access (template, F_OK) < 0) {
        g_printerr ("We did not write anything to stdout (%d).\n", errno);
        g_test_fail ();
    }

    /* Now ensure we've logged exactly what was expected. */
    if ((fp = fopen (template, "r")) == NULL) {
        g_printerr ("Could not open temporary stdout (%d).\n", errno);
        g_test_fail ();
    }

    fread (buf, 512, 1, fp);
    if (strcmp (buf, expected) != 0) {
        g_printerr ("We did not write what was expected to stdout:\n%s", buf);
        g_test_fail ();
    }

    /* Clean up */
    if (fclose (fp))
        g_printerr ("Could not close the file pointer (%d).\n", errno);

    if (unlink (template) < 0) {
        if (errno != ENOENT)
            g_test_fail ();
    }
out:
    dup2 (fd, fileno (stdout));
    close (fd);
    clearerr (stdout);
    fsetpos (stdout, &pos);
}

void
test_logging_syslog (void)
{
    char template[] = "/tmp/XXXXXX";

    char buf[512] = {0};
    FILE* fp = NULL;

    extern int logging_flags;
    const char *expected = "whoopsie: Hello.\n";

    logging_flags = LOG_PERROR;
    foreground = 0;

    int fd;
    fpos_t pos;

    /* http://c-faq.com/stdio/undofreopen.html */
    fflush (stderr);
    fgetpos (stderr, &pos);
    fd = dup (fileno (stderr));

    tmpnam (template);
    if (freopen (template, "w", stderr) == NULL) {
        g_print ("Could not open temporary stderr (%d).\n", errno);
        g_test_fail ();
        goto out;
    }

    open_log ();
    log_msg ("Hello.\n");
    fflush (stderr);
    close_log ();

    /* Did we write a log file? */
    if (access (template, F_OK) < 0) {
        g_print ("We did not write anything to stderr (%d).\n", errno);
        g_test_fail ();
    }

    /* Now ensure we've logged exactly what was expected. */
    if ((fp = fopen (template, "r")) == NULL) {
        g_print ("Could not open temporary stderr (%d).\n", errno);
        g_test_fail ();
    }

    fread (buf, 512, 1, fp);
    if (strcmp (buf, expected) != 0) {
        g_print ("We did not write what was expected to stderr:\n%s", buf);
        g_test_fail ();
    }

    /* Clean up */
    if (fclose (fp))
        g_print ("Could not close the file pointer (%d).\n", errno);

    if (unlink (template) < 0) {
        if (errno != ENOENT)
            g_test_fail ();
    }
out:
    dup2 (fd, fileno (stderr));
    close (fd);
    clearerr (stderr);
    fsetpos (stderr, &pos);
}

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);
    g_test_add_func ("/whoopsie/logging",
                     test_logging);
    g_test_add_func ("/whoopsie/logging-syslog",
                     test_logging_syslog);
    return g_test_run ();
}
