/*
 * Copyright (c) 2010-2012 Zmanda Inc.  All Rights Reserved.
 *
 * 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, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
 *
 * Contact information: Carbonite Inc., 756 N Pastoria Ave
 * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
 */

#include "amanda.h"
#include "testutils.h"
#include "fileheader.h"

#define TAPE_HEADER(hdr) ((hdr)->type == F_TAPESTART || (hdr)->type == F_TAPEEND)

static int n_round_trips = 0;

/* actually test the round trip */
static int
try_rt(dumpfile_t *hdr)
{
    char *strval;
    size_t size;
    dumpfile_t hdr2;

    size = 0;
    strval = build_header(hdr, &size, 32768);
    g_assert(strval != NULL);
    fh_init(&hdr2);
    parse_file_header(strval, &hdr2, size);

    if (!headers_are_equal(hdr, &hdr2)) {
	tu_dbg("*** build_header of:\n");
	dump_dumpfile_t(hdr);
	tu_dbg("*** gives:\n");
	tu_dbg("%s", strval);
	tu_dbg("*** which becomes:\n");
	dump_dumpfile_t(&hdr2);
	return 0;
    }

    n_round_trips++;

    dumpfile_free_data(&hdr2);
    return 1;
#define PREV_RT try_rt
}

static int
rt_partnum(dumpfile_t *hdr)
{
    if (hdr->type == F_SPLIT_DUMPFILE) {
	hdr->partnum = 1;
	hdr->totalparts = 2;
	if (!PREV_RT(hdr)) return 0;
	hdr->partnum = 2;
	hdr->totalparts = 2;
	if (!PREV_RT(hdr)) return 0;
	hdr->partnum = 2;
	hdr->totalparts = -1;
	if (!PREV_RT(hdr)) return 0;
    } else if (hdr->type == F_DUMPFILE) {
	hdr->partnum = 1;
	hdr->totalparts = 1;
	if (!PREV_RT(hdr)) return 0;
    } else {
	hdr->partnum = 0;
	hdr->totalparts = 0;
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_partnum
}

static int
rt_compress(dumpfile_t *hdr)
{
    if (TAPE_HEADER(hdr)) {
	hdr->compressed = 0;
	strcpy(hdr->comp_suffix, "");
	if (!PREV_RT(hdr)) return 0;
    } else {
	hdr->compressed = 0;
	strcpy(hdr->comp_suffix, "");
	if (!PREV_RT(hdr)) return 0;
	hdr->compressed = 1;
	strcpy(hdr->comp_suffix, ".gz");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_compress
}

static int
rt_encrypt(dumpfile_t *hdr)
{
    if (TAPE_HEADER(hdr)) {
	hdr->encrypted = 0;
	strcpy(hdr->encrypt_suffix, "");
	if (!PREV_RT(hdr)) return 0;
    } else {
	hdr->encrypted = 0;
	strcpy(hdr->encrypt_suffix, "");
	if (!PREV_RT(hdr)) return 0;

	/* (note: Amanda seems to use 'enc' as the only suffix, and it doesn't
	 * really use it as a suffix; using .aes here ensures that the fileheader
	 * code can handle real suffixes, too */
	hdr->encrypted = 1;
	strcpy(hdr->encrypt_suffix, ".aes");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_encrypt
}

static int
rt_disk(dumpfile_t *hdr)
{
    if (TAPE_HEADER(hdr)) {
	strcpy(hdr->disk, "");
	if (!PREV_RT(hdr)) return 0;
    } else {
	strcpy(hdr->disk, "/usr");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->disk, ""); /* should be quoted */
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_disk
}

static int
rt_partial(dumpfile_t *hdr)
{
    if (TAPE_HEADER(hdr)) {
	hdr->is_partial = 0;
	if (!PREV_RT(hdr)) return 0;
    } else {
	hdr->is_partial = 1;
	if (!PREV_RT(hdr)) return 0;
	hdr->is_partial = 0;
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_partial
}

static int
rt_application(dumpfile_t *hdr)
{
    if (TAPE_HEADER(hdr)) {
	strcpy(hdr->application, "");
	if (!PREV_RT(hdr)) return 0;
    } else {
	strcpy(hdr->application, "MS-PAINT");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_application
}

static int
rt_dle_str(dumpfile_t *hdr)
{
    if (TAPE_HEADER(hdr)) {
	strcpy(hdr->dle_str, "");
	if (!PREV_RT(hdr)) return 0;
    } else {
	hdr->dle_str = g_strdup("");
	if (!PREV_RT(hdr)) return 0;
	hdr->dle_str = g_strdup("no-newline");
	if (!PREV_RT(hdr)) return 0;
	hdr->dle_str = g_strdup("ENDDLE\nmy dle\nENDDLE3");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_dle_str
}

static int
rt_program(dumpfile_t *hdr)
{
    if (TAPE_HEADER(hdr)) {
	strcpy(hdr->program, "");
	if (!PREV_RT(hdr)) return 0;
    } else {
	strcpy(hdr->program, "CHECK");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_program
}

static int
rt_encrypt_prog(dumpfile_t *hdr)
{
    /* only do this for F_DUMPFILE, just to spare some repetitive testing */
    if (hdr->type == F_DUMPFILE) {
	strcpy(hdr->srv_encrypt, "");
	strcpy(hdr->clnt_encrypt, "");
	strcpy(hdr->srv_decrypt_opt, "");
	strcpy(hdr->clnt_decrypt_opt, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->srv_encrypt, "my-enc");
	strcpy(hdr->clnt_encrypt, "");
	strcpy(hdr->srv_decrypt_opt, "");
	strcpy(hdr->clnt_decrypt_opt, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->srv_encrypt, "my-enc");
	strcpy(hdr->clnt_encrypt, "");
	strcpy(hdr->srv_decrypt_opt, "-foo");
	strcpy(hdr->clnt_decrypt_opt, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->srv_encrypt, "");
	strcpy(hdr->clnt_encrypt, "its-enc");
	strcpy(hdr->srv_decrypt_opt, "");
	strcpy(hdr->clnt_decrypt_opt, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->srv_encrypt, "");
	strcpy(hdr->clnt_encrypt, "its-enc");
	strcpy(hdr->srv_decrypt_opt, "");
	strcpy(hdr->clnt_decrypt_opt, "-foo");
	if (!PREV_RT(hdr)) return 0;
    } else {
	strcpy(hdr->srv_encrypt, "");
	strcpy(hdr->clnt_encrypt, "");
	strcpy(hdr->srv_decrypt_opt, "");
	strcpy(hdr->clnt_decrypt_opt, "");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_encrypt_prog
}

static int
rt_compprog(dumpfile_t *hdr)
{
    /* only do this for F_DUMPFILE, just to spare some repetitive testing */
    if (hdr->type == F_DUMPFILE) {
	strcpy(hdr->srvcompprog, "");
	strcpy(hdr->clntcompprog, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->srvcompprog, "my-comp-prog");
	strcpy(hdr->clntcompprog, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->srvcompprog, "");
	strcpy(hdr->clntcompprog, "its-comp-prog");
	if (!PREV_RT(hdr)) return 0;
    } else {
	strcpy(hdr->srvcompprog, "");
	strcpy(hdr->clntcompprog, "");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_compprog
}

static int
rt_cmds(dumpfile_t *hdr)
{
    /* only do this for F_SPLIT_DUMPFILE, just to spare some repetitive testing */
    if (hdr->type == F_SPLIT_DUMPFILE) {
	strcpy(hdr->recover_cmd, "");
	strcpy(hdr->uncompress_cmd, "");
	strcpy(hdr->decrypt_cmd, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->recover_cmd, "get my data back");
	strcpy(hdr->uncompress_cmd, "");
	strcpy(hdr->decrypt_cmd, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->recover_cmd, "get my data back");
	strcpy(hdr->uncompress_cmd, "make my data bigger |");
	strcpy(hdr->decrypt_cmd, "");
	if (!PREV_RT(hdr)) return 0;
	strcpy(hdr->recover_cmd, "get my data back");
	strcpy(hdr->uncompress_cmd, "make my data bigger |");
	strcpy(hdr->decrypt_cmd, "unscramble it too |");
	if (!PREV_RT(hdr)) return 0;
    } else {
	strcpy(hdr->recover_cmd, "");
	strcpy(hdr->uncompress_cmd, "");
	strcpy(hdr->decrypt_cmd, "");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_cmds
}

static int
rt_cont_filename(dumpfile_t *hdr)
{
    if (hdr->type == F_DUMPFILE || hdr->type == F_CONT_DUMPFILE) {
	strcpy(hdr->cont_filename, "/next/file");
	if (!PREV_RT(hdr)) return 0;
    } else {
	strcpy(hdr->cont_filename, "");
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_cont_filename
}

static int
rt_dumplevel(dumpfile_t *hdr)
{
    if (TAPE_HEADER(hdr)) {
	hdr->dumplevel = 0;
	if (!PREV_RT(hdr)) return 0;
    } else {
	hdr->dumplevel = 0;
	if (!PREV_RT(hdr)) return 0;
	hdr->dumplevel = 1;
	if (!PREV_RT(hdr)) return 0;
    }
    return 1;
#undef PREV_RT
#define PREV_RT rt_dumplevel
}

static int
rt_name(dumpfile_t *hdr)
{
    if (hdr->type == F_TAPEEND)
	strcpy(hdr->name, "");
    else if (TAPE_HEADER(hdr))
	strcpy(hdr->name, "TEST-LABEL");
    else 
	strcpy(hdr->name, "batcave-web");
    if (!PREV_RT(hdr)) return 0;
    return 1;
#undef PREV_RT
#define PREV_RT rt_name
}

static int
rt_type(dumpfile_t *hdr)
{
    hdr->type = F_DUMPFILE;
    if (!PREV_RT(hdr)) return 0;
    hdr->type = F_CONT_DUMPFILE;
    if (!PREV_RT(hdr)) return 0;
    hdr->type = F_SPLIT_DUMPFILE;
    if (!PREV_RT(hdr)) return 0;
    hdr->type = F_TAPESTART;
    if (!PREV_RT(hdr)) return 0;
    hdr->type = F_TAPEEND;
    if (!PREV_RT(hdr)) return 0;
    return 1;
#undef PREV_RT
#define PREV_RT rt_type
}

/* one function for each field; each fn calls the one above */
static gboolean
test_roundtrip(void)
{
    int rv;
    dumpfile_t hdr;
    fh_init(&hdr);

    /* set up some basic, constant values */
    strcpy(hdr.datestamp, "20100102030405");
    strcpy(hdr.name, "localhost");

    rv = PREV_RT(&hdr);
    tu_dbg("%d round-trips run\n", n_round_trips);
    return (rv) ? TRUE : FALSE;
}

/* doc

encrypted + encrypt_suffix (N special)
compressed + comp_suffix (N special)
blocksize not parsed
partnum/totalparts interaction
{srv,clnt}{compprog,_encrypt} pairs
uncompress/decrypt_cmd invalid without recover_cmd
uncompress/decrypt_cmd require trailing |
default to uncompress if only 2 cmds

*/

int
main(int argc, char **argv)
{
    static TestUtilsTest tests[] = {
        TU_TEST(test_roundtrip, 90),
        TU_END()
    };

    glib_init();

    return testutils_run_tests(argc, argv, tests);
}
