/* FIXME: horribly incomplete */
#include "wvtest.h"
#include "wvlog.h"
#include "wvlogbuffer.h"
#include "wvlogfile.h"
#include "wvfileutils.h"


WVTEST_MAIN("extremely basic test")
{
    // this test just basically helps see if there's an fd or memory leak
    // caused by creating/using a wvlog...
    WvLog log("logtest", WvLog::Info);
    log("Hello!\n");
    WVPASS(log.isok());
}


WVTEST_MAIN("line-breaking logic")
{
    WvLogBuffer logbuffer(10);
    WvLog log1("log", WvLog::Info);
    WvLog log2(log1.split(WvLog::Debug));
    WvLog log3("other log", WvLog::Info);

    log1("first part");
    log2("second part");
    log1("third part");
    log3("fourth part");
    log2("Message: ");
    log1(WvLog::Debug, "this is the message\n");

    WvLogBuffer::MsgList::Iter i(logbuffer.messages());
    i.rewind();

    WVPASS(i.next());
    WVPASSEQ(i->level, WvLog::Info);
    WVPASSEQ(i->source, "log");
    WVPASSEQ(i->message, "first part");

    WVPASS(i.next());
    WVPASSEQ(i->level, WvLog::Debug);
    WVPASSEQ(i->source, "log");
    WVPASSEQ(i->message, "second part");

    WVPASS(i.next());
    WVPASSEQ(i->level, WvLog::Info);
    WVPASSEQ(i->source, "log");
    WVPASSEQ(i->message, "third part");

    WVPASS(i.next());
    WVPASSEQ(i->level, WvLog::Info);
    WVPASSEQ(i->source, "other log");
    WVPASSEQ(i->message, "fourth part");

    WVPASS(i.next());
    WVPASSEQ(i->level, WvLog::Debug);
    WVPASSEQ(i->source, "log");
    WVPASSEQ(i->message, "Message: this is the message");

    WVFAIL(i.next());
}

WVTEST_MAIN("timestamps")
{
    WvString logfilename = wvtmpfilename("wvlog-timestamps");
    WvLogFileBase logfile(logfilename, WvLog::Debug);
    WvLog log(__FUNCTION__, WvLog::Debug);
    time_t first_time = time(NULL);
    log("First message\n");
    while (time(NULL) - first_time < 2)
        sleep(1);
    log("Second message\n");
    logfile.close();

    WvFile file(logfilename, O_RDONLY);
    WVPASS(file.isok());
    // 0123456789012345678901
    // Nov 10 10:13:15 GMT-4: 
    WvString first_timestamp = file.getline();
    if (first_timestamp.len() >= 21)
	first_timestamp.edit()[21] = '\0';
    wvout->print("first timestamp: %s\n", first_timestamp);    
    WvString second_timestamp = file.getline();
    if (second_timestamp.len() >= 21)
	second_timestamp.edit()[21] = '\0';
    wvout->print("second timestamp: %s\n", second_timestamp);    
    WVFAILEQ(first_timestamp, second_timestamp);

    file.close();
    WVPASS(unlink(logfilename) == 0);
}

WVTEST_MAIN("keep single log lines together")
{
    WvString logfilename = wvtmpfilename("wvlog-together");
    fprintf(stderr, "log file is: '%s'\n", logfilename.cstr());
    
    {
	// WvFile f(logfilename, O_WRONLY|O_CREAT);
	int fd = open(logfilename, O_WRONLY|O_CREAT, 0777);
	if (fd < 0) perror("open");
	if (close(fd) != 0) perror("close");
    }
    if (unlink(logfilename) != 0)
	perror("unlink");
    
    WvLogFileBase logfile(logfilename, WvLog::Debug);
    WvLog log(__FUNCTION__, WvLog::Debug);
    time_t first_time = time(NULL);
    log("First message: ");
    while (time(NULL) - first_time < 2)
        sleep(1);
    log("Second message\n");
    logfile.close();

    WvFile file(logfilename, O_RDONLY);
    WVPASS(file.isok());

    WvString line1 = file.getline();
    WvString line2 = file.getline();

    wvout->print("line 1: %s\n", line1);

    // we want both messages on a single log line
    WVPASS(!line2);
    WVPASS(strstr(line1.cstr(), "First"));
    WVPASS(strstr(line1.cstr(), "Second"));

    file.close();
    WVPASS(unlink(logfilename) == 0);
}

class WvNoisyLogRcv : public WvLogConsole
{
    WvString noise;
    WvLog sublog;
    
public:
    WvNoisyLogRcv(WvStringParm _noise, int fd, WvLog::LogLevel max_level) : 
        WvLogConsole(fd, max_level),
        noise(_noise),
        sublog("WvNoisyLogRcv", max_level)
    {
    }

    void log(WvStringParm source, int _loglevel,
            const char *_buf, size_t len)
    {
        sublog("%s\n", noise);
        return WvLogConsole::log(source, _loglevel, _buf, len);
    }
};

// Test that if a log receiver generates a log message itself while logging,
// that we log a warning about it and don't recurse endlessly.
WVTEST_MAIN("Recursion avoidance")
{
    WvString noise("Recursive noise");
    WvNoisyLogRcv noisy(noise, dup(1), WvLog::Debug5);

#ifdef WIN32
    mkdir("/tmp");
#endif
    WvString logfilename("/tmp/wvlog-recursive-test.%s", getpid());
    WvLogFileBase logfile(logfilename, WvLog::Debug5);
    
    if (!WVPASS(logfile.isok()))
    {
	wverr->print("open %s: %s\n", logfilename, logfile.errstr());
	return;
    }
    
    WvLog log("Regular log", WvLog::Error);
    WvString logmsg("The pebble that starts an avalanche...");
    log(logmsg);
    logfile.close();

    WvFile file(logfilename, O_RDONLY);
    if (!WVPASS(file.isok()))
    {
	wverr->print("open %s: %s\n", logfilename, file.errstr());
	return;
    }

    // Test that we received all the log messages we were due
    WVPASS(strstr(file.getline(), "Too many extra log messages "
                "written while writing to the log.  Suppressing "
                "additional messages."));
    for (int i = 0; i < 6; ++i)
        WVPASS(strstr(file.getline(), noise.cstr()));

    WVPASS(strstr(file.getline(), logmsg.cstr()));

    // Cleanup
    file.close();
    WVPASSEQ(unlink(logfilename), 0);
}

#if 0
WVTEST_MAIN("wvlog performance")
{
    WvString logfilename = wvtmpfilename("wvlog-timestamps");
    WvLogFileBase logfile(logfilename, WvLog::Debug);
    WvLog log(__FUNCTION__, WvLog::Debug);
    
    time_t start;
    start = time(NULL);
    while (time(NULL) == start)
        usleep(1000);
    start = time(NULL);

    int count = 0;
    while (time(NULL) - start < 10)
        log("Message %s\n", count++);

    wvout->print("Total %s log messages\n", count);

    WVPASS(unlink(logfilename) == 0);
}
#endif
