/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * testbase.c
 *
 *  Created on: 02.09.2010
 *      Author: Hendrik Helwich <h.helwich@tarent.de>
 */

/*
 * This program 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 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 Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
 */

#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> /* getcwd() definition */
#include <sys/param.h> /* MAXPATHLEN definition */
#include <libecal/e-cal-component.h>
#include <kolab-conv.h>
#include <evolution/evolution.h>
#include <kolab/kolab.h>
#include <kolab/kolab-util.h>
#include <structs/contact.h>
#include <logging.h>
#include "email-parser.h"
#include "test-convert-setup.h"
#include "main.h"
#include "testbase.h"

/**
 * A structure which contains the needed arguments of a test
 */


/**
 * Can be used inside unit tests.
 * If the given error object contains an error, the given formatted message
 * and the error message are logged and the test will be stopped.
 *
 * @param  error
 *         a glib error structure
 * @param  fmt
 *         a formatted message like in printf
 */
static void
check_error (GError *error, gchar *fmt, ...)
{
	if (error != NULL) {
		va_list ap;
		va_start (ap, fmt);
		g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, ap);
		va_end(ap);
		g_message("%s", error->message);
		g_assert_not_reached();
	}
}

/**
 * Reads a kolab email file to a kolab mail struct.
 * Exists if an error occurs.
 *
 * @param  filename
 *         A filename of a kolab email file
 * @return A kolab mail struct
 */
static Kolab_conv_mail*
read_kolab_email_file_tested (const gchar* filename, gint *stage)
{
	GError *error = NULL;
	Kolab_conv_mail *mail = NULL;

	/* read kolab mail file to the kolab mail struct */
	g_message("reading email file %s to a kolab mail struct", filename);
	mail = read_kolab_email_file (filename, &error);
	check_error (error, "error while reading kolab email file %s", filename);
	*stage |= TEST_STAGE_FILE_TO_KMAIL;
	return mail;
}

static void
write_kolab_email_file_tested (const gchar* filename, Kolab_conv_mail* mail, gint *stage)
{
	GError *error = NULL;
	/* write temporary kolab mail file */
	g_message("writing kolab mail struct to email file %s", filename);
	write_kolab_email_file(mail, filename, &error);
	check_error (error, "error while writing kolab email file %s", filename);
	*stage |= TEST_STAGE_KMAIL_TO_FILE;
}

static gchar*
create_evolution_vcard_tested_I_contact (const EContact* econtact, gint *stage)
{
	EVCardFormat version = EVC_FORMAT_VCARD_30;
	gchar *vcard_str = NULL;

	g_message("serializing evolution contact to vCard 3.0 string");

	vcard_str = e_vcard_to_string ((EVCard *) econtact, version);

	*stage |= TEST_STAGE_EVO_TO_FILE;
	return vcard_str;
}

static gchar*
create_evolution_vcard_tested (const ECalComponentWithTZ* epim, gint *stage)
{
	icalcomponent *ical_vevent = NULL;
	icalcomponent *ical_vcal = NULL;
	icalcomponent *ical_vtz = NULL;
	gchar *ical_str = NULL;

	g_log ("libekolabconv", G_LOG_LEVEL_MESSAGE,
			"serializing evolution event to vCard 3.0 string");
	ical_vevent = e_cal_component_get_icalcomponent (
			(ECalComponent*) epim->maincomp);
	ical_vcal = icalcomponent_new_vcalendar ();
	if (epim->timezone != ((void *) 0)) {
		ical_vtz = e_cal_component_get_icalcomponent (
				(ECalComponent*) epim->timezone);
		icalcomponent_add_component (ical_vcal, ical_vtz);
	}
	icalcomponent_add_component (ical_vcal, ical_vevent);
	ical_str = icalcomponent_as_ical_string (ical_vcal);
	/* free allocated resources */
	if (ical_vtz != NULL)
		icalcomponent_remove_component(ical_vcal, ical_vtz);
	icalcomponent_remove_component(ical_vcal, ical_vevent);
	icalcomponent_free(ical_vcal);
	*stage |= TEST_STAGE_EVO_TO_FILE;
	return ical_str;
}


static gchar*
create_evolution_vcard_tested_I_event (const ECalComponentWithTZ* eevent, gint *stage)
{
	return create_evolution_vcard_tested(eevent, stage);
}

static gchar*
create_evolution_vcard_tested_I_task (const ECalComponentWithTZ* eetask, gint *stage)
{
	return create_evolution_vcard_tested(eetask, stage);
}

static gchar*
create_evolution_vcard_tested_I_note (const ECalComponentWithTZ* enote, gint *stage)
{
	return create_evolution_vcard_tested(enote, stage);
}

static EContact*
process_evolution_vcard_tested_I_contact (const gchar* vcard_str, gint *stage)
{
	EContact *econtact = NULL;

	g_message("deserializing evolution contact from vCard 3.0 string");
	econtact = e_contact_new_from_vcard(vcard_str);
	*stage |= TEST_STAGE_FILE_TO_EVO;
	return econtact;
}

static ECalComponentWithTZ*
process_evolution_vcard_tested (const gchar* vcard_str, icalcomponent_kind kind, gint *stage)
{
	icalcomponent *ical_vcal = NULL;
	icalcomponent *ical_vevent = NULL;
	icalcomponent *ical_vtz = NULL;
	ECalComponent *epim = NULL;
	ECalComponent *etz = NULL;
	ECalComponentWithTZ *ectz = NULL;
	gboolean success = FALSE;

	g_message("deserializing evolution instance from vCard 3.0 string");
	ical_vcal = icalcomponent_new_from_string( vcard_str );
	ical_vevent = icalcomponent_get_first_component ( ical_vcal, kind );
	epim = e_cal_component_new();
	success = e_cal_component_set_icalcomponent (epim,  icalcomponent_new_clone ( ical_vevent ));
	g_assert(success);
	ical_vtz = icalcomponent_get_first_component ( ical_vcal, ICAL_VTIMEZONE_COMPONENT );
	etz = e_cal_component_new();
	success =  e_cal_component_set_icalcomponent (etz,  icalcomponent_new_clone ( ical_vtz ));
	g_assert(success);
	ectz = g_new0(ECalComponentWithTZ, 1);
	ectz->maincomp = epim;
	ectz->timezone = etz;
	*stage |= TEST_STAGE_FILE_TO_EVO;
	icalcomponent_free(ical_vcal);
	return ectz;
}

static ECalComponentWithTZ*
process_evolution_vcard_tested_I_event (const gchar* vcard_str, gint *stage)
{
	return process_evolution_vcard_tested(vcard_str, ICAL_VEVENT_COMPONENT, stage);
}

static ECalComponentWithTZ*
process_evolution_vcard_tested_I_task (const gchar* vcard_str, gint *stage)
{
	return process_evolution_vcard_tested(vcard_str, ICAL_VTODO_COMPONENT, stage);
}

static ECalComponentWithTZ*
process_evolution_vcard_tested_I_note (const gchar* vcard_str, gint *stage)
{
	return process_evolution_vcard_tested(vcard_str, ICAL_VJOURNAL_COMPONENT, stage);
}

static gchar*
read_text_file_tested (const gchar* filename)
{
	GError *error = NULL;
	gchar *contents = NULL;
	gboolean success = FALSE;
	g_message("reading file %s to memory", filename);
	success = g_file_get_contents(filename, &contents, NULL, &error);
	g_assert(success);
	check_error (error, "error while processing kolab email struct");
	return contents;
}

static void
free_after_test(gpointer ptr)
{
	free_mem_after_test = g_list_append(free_mem_after_test, ptr);
}

#define process_kolab_tested(PIM_TYPE) \
static PIM_TYPE*\
process_kolab_tested_##PIM_TYPE (const Kolab_conv_mail* kmail, void\
(*testData) (const PIM_TYPE*, gint stage), gint *stage)\
{\
	GError *error = NULL;\
	PIM_TYPE *ipim = NULL;\
	/* convert kolab mail struct to a typed interchange struct */\
	g_message("converting kolab mail struct to an interchange struct");\
	ipim = conv_kolab_conv_mail_to_##PIM_TYPE (kmail, &error);\
	check_error (error, "error while processing kolab email struct");\
	*stage |= TEST_STAGE_KMAIL_TO_INTERN;\
	/* test interchange struct */\
	g_message("testing interchange struct");\
	(*testData) (ipim, *stage);\
	return ipim;\
}

process_kolab_tested(I_contact)
process_kolab_tested(I_event)
process_kolab_tested(I_task)
process_kolab_tested(I_note)

#define create_kolab_tested(PIM_TYPE) \
static Kolab_conv_mail*\
create_kolab_tested_##PIM_TYPE (PIM_TYPE* ipim, void\
(*testData) (const PIM_TYPE*, gint stage), gint *stage)\
{\
	GError *error = NULL;\
	Kolab_conv_mail *mail = NULL;\
	(void)testData;\
	\
	/* convert kolab mail struct to a typed interchange struct */\
	g_message("converting interchange struct to kolab mail struct");\
	mail = conv_##PIM_TYPE##_to_kolab_conv_mail (&ipim, &error);\
	check_error (error, "error while creating kolab email struct");\
	g_assert(ipim == NULL);\
	*stage |= TEST_STAGE_INTERN_TO_KMAIL;\
	log_xml_part(mail);\
	return mail;\
}

create_kolab_tested(I_contact)
create_kolab_tested(I_event)
create_kolab_tested(I_task)
create_kolab_tested(I_note)

#define process_evolution_tested(EVO_TYPE, PIM_TYPE) \
static PIM_TYPE*\
process_evolution_tested_##PIM_TYPE (const EVO_TYPE* epim, void\
(*testData) (const PIM_TYPE*, gint stage), gint *stage)\
{\
	GError *error = NULL;\
	PIM_TYPE *ipim = NULL;\
	/* convert to interchange struct again */\
	g_message("converting evolution contact to interchange contact struct");\
	ipim = conv_##EVO_TYPE##_to_##PIM_TYPE (epim, &error);\
	check_error (error, "error while processing evolution contact");\
	*stage |= TEST_STAGE_EVO_TO_INTERN;\
	\
	/* interchange struct should not be touched */\
	g_message("testing interchange contact struct");\
	(*testData) (ipim, *stage);\
	return ipim;\
}

process_evolution_tested(EContact, I_contact)
process_evolution_tested(ECalComponentWithTZ, I_event)
process_evolution_tested(ECalComponentWithTZ, I_task)
process_evolution_tested(ECalComponentWithTZ, I_note)

#define create_evolution_tested(EVO_TYPE, PIM_TYPE) \
static EVO_TYPE*\
create_evolution_tested_##PIM_TYPE (PIM_TYPE* ipim, void\
(*testData) (const PIM_TYPE*, gint stage), gint *stage)\
{\
	GError *error = NULL;\
	EVO_TYPE *epim = NULL;\
	gint dummystage = 0;\
	gchar *vcard = NULL;\
	(void)testData;\
	/* convert to interchange struct again */\
	g_message("converting interchange contact struct to an evolution contact");\
	epim = conv_##PIM_TYPE##_to_##EVO_TYPE (&ipim, &error);\
	check_error (error, "error while creating evolution contact");\
	g_assert(ipim == NULL);\
	vcard = create_evolution_vcard_tested_##PIM_TYPE(epim, &dummystage);\
	log_debug("%s", vcard);\
	g_free(vcard);\
	*stage |= TEST_STAGE_INTERN_TO_EVO;\
	return epim;\
}

/* create struct typedefs to eliminate warnings */
typedef process_pim_type(I_contact) test_args_I_contact;
typedef process_pim_type(I_event) test_args_I_event;
typedef process_pim_type(I_task) test_args_I_task;
typedef process_pim_type(I_note) test_args_I_note;


create_evolution_tested(EContact, I_contact)
create_evolution_tested(ECalComponentWithTZ, I_event)
create_evolution_tested(ECalComponentWithTZ, I_task)
create_evolution_tested(ECalComponentWithTZ, I_note)

static void
free_I_contact(I_contact **ipim)
{
	generic_g_list_free (&(*ipim)->common->kolab_attachment_store, kolabconv_free_kmail_part);
	free_i_contact(ipim);
}

static void
free_I_event(I_event **ipim)
{
	generic_g_list_free (&(*ipim)->incidence->common->kolab_attachment_store, kolabconv_free_kmail_part);
	free_i_event(ipim);
}

static void
free_I_task(I_task **ipim)
{
	generic_g_list_free (&(*ipim)->incidence->common->kolab_attachment_store, kolabconv_free_kmail_part);
	free_i_task(ipim);
}

static void
free_I_note (I_note **ipim)
{
	generic_g_list_free (&(*ipim)->common->kolab_attachment_store, kolabconv_free_kmail_part);
	free_i_note (ipim);
}


#define test_convert_kolab_read_mailfile_read_kolab(PIM_TYPE) \
static void \
test_convert_kolab_read_mailfile_read_kolab_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	Kolab_conv_mail *kmail = NULL;\
	PIM_TYPE *ipim = NULL;\
	kolabconv_initialize ();\
	\
	kmail = read_kolab_email_file_tested (args->filename, &stage);\
	log_xml_part(kmail);\
	ipim = process_kolab_tested_##PIM_TYPE(kmail, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	kolabconv_free_kmail(kmail);\
	\
	kolabconv_shutdown ();\
}

test_convert_kolab_read_mailfile_read_kolab(I_contact)
test_convert_kolab_read_mailfile_read_kolab(I_event)
test_convert_kolab_read_mailfile_read_kolab(I_task)
test_convert_kolab_read_mailfile_read_kolab(I_note)

static void
free_EContact(EContact *contact)
{
	kolabconv_free_econtact(contact);
}

static void
free_ECalComponentWithTZ(ECalComponentWithTZ *comp)
{
	kolabconv_free_ecalendar(comp);
}


#define test_convert_evolution_read_vcard_read_evolution(EVO_TYPE, PIM_TYPE) \
static void \
test_convert_evolution_read_vcard_read_evolution_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	gchar *vcard = NULL;\
	EVO_TYPE *epim = NULL;\
	PIM_TYPE *ipim = NULL;\
	kolabconv_initialize ();\
	vcard = read_text_file_tested(args->filename);\
	g_debug("VCard:\n%s", vcard);\
	epim = process_evolution_vcard_tested_##PIM_TYPE(vcard, &stage);\
	g_free(vcard);\
	ipim = process_evolution_tested_##PIM_TYPE (epim, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	free_##EVO_TYPE(epim);\
	/* TODO: log ipim (print_contact(ipim);*/\
	kolabconv_shutdown ();\
}

test_convert_evolution_read_vcard_read_evolution(EContact, I_contact)
test_convert_evolution_read_vcard_read_evolution(ECalComponentWithTZ, I_event)
test_convert_evolution_read_vcard_read_evolution(ECalComponentWithTZ, I_task)
test_convert_evolution_read_vcard_read_evolution(ECalComponentWithTZ, I_note)

#define test_convert_evolution_write_evolution(EVO_TYPE, PIM_TYPE) \
static void \
test_convert_evolution_write_evolution_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	gchar *vcard = NULL;\
	EVO_TYPE *epim = NULL;\
	EVO_TYPE *epim2 = NULL;\
	PIM_TYPE *ipim = NULL;\
	kolabconv_initialize ();\
	vcard = read_text_file_tested(args->filename);\
	epim = process_evolution_vcard_tested_##PIM_TYPE(vcard, &stage);\
	g_free(vcard);\
	ipim = process_evolution_tested_##PIM_TYPE (epim, args->validate_op, &stage);\
	free_##EVO_TYPE(epim);\
	g_message("preconditions ok");\
	epim2 = create_evolution_tested_##PIM_TYPE (ipim, args->validate_op, &stage);\
	vcard = create_evolution_vcard_tested_##PIM_TYPE(epim2, &stage);\
	log_debug("%s", vcard);\
	g_free(vcard);\
	ipim = process_evolution_tested_##PIM_TYPE (epim2, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	free_##EVO_TYPE(epim2);\
	kolabconv_shutdown ();\
}

test_convert_evolution_write_evolution(EContact, I_contact)
test_convert_evolution_write_evolution(ECalComponentWithTZ, I_event)
test_convert_evolution_write_evolution(ECalComponentWithTZ, I_task)
test_convert_evolution_write_evolution(ECalComponentWithTZ, I_note)

#define test_convert_evolution_write_vcard(EVO_TYPE, PIM_TYPE) \
static void \
test_convert_evolution_write_vcard_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	gchar *vcard = NULL;\
	gchar *vcard_str = NULL;\
	EVO_TYPE *epim = NULL;\
	EVO_TYPE *epim2 = NULL;\
	PIM_TYPE *ipim = NULL;\
	kolabconv_initialize ();\
	vcard = read_text_file_tested(args->filename);\
	epim = process_evolution_vcard_tested_##PIM_TYPE(vcard, &stage);\
	g_free(vcard);\
	g_message("preconditions ok");\
	vcard_str = create_evolution_vcard_tested_##PIM_TYPE(epim, &stage);\
	free_##EVO_TYPE(epim);\
	g_debug("VCard:\n%s", vcard_str);\
	epim2 = process_evolution_vcard_tested_##PIM_TYPE(vcard_str, &stage);\
	g_free(vcard_str);\
	ipim = process_evolution_tested_##PIM_TYPE (epim2, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	free_##EVO_TYPE(epim2);\
	kolabconv_shutdown ();\
}

test_convert_evolution_write_vcard(EContact, I_contact)
test_convert_evolution_write_vcard(ECalComponentWithTZ, I_event)
test_convert_evolution_write_vcard(ECalComponentWithTZ, I_task)
test_convert_evolution_write_vcard(ECalComponentWithTZ, I_note)

#define test_convert_evolution_read_write_kolab(EVO_TYPE, PIM_TYPE) \
static void \
test_convert_evolution_read_write_kolab_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	gchar *vcard = NULL;\
	EVO_TYPE *epim = NULL;\
	PIM_TYPE *ipim = NULL;\
	Kolab_conv_mail *kmail = NULL;\
	kolabconv_initialize ();\
	vcard = read_text_file_tested(args->filename);\
	epim = process_evolution_vcard_tested_##PIM_TYPE(vcard, &stage);\
	g_free(vcard);\
	ipim = process_evolution_tested_##PIM_TYPE (epim, args->validate_op, &stage);\
	free_##EVO_TYPE(epim);\
	g_message("preconditions ok");\
	kmail = create_kolab_tested_##PIM_TYPE (ipim, args->validate_op, &stage);\
	log_xml_part(kmail);\
	ipim = process_kolab_tested_##PIM_TYPE (kmail, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	kolabconv_free_kmail(kmail);\
	kolabconv_shutdown ();\
}

test_convert_evolution_read_write_kolab(EContact, I_contact)
test_convert_evolution_read_write_kolab(ECalComponentWithTZ, I_event)
test_convert_evolution_read_write_kolab(ECalComponentWithTZ, I_task)
test_convert_evolution_read_write_kolab(ECalComponentWithTZ, I_note)

#define test_convert_evolution_read_write_mailfile(EVO_TYPE, PIM_TYPE) \
static void \
test_convert_evolution_read_write_mailfile_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	gchar *vcard = NULL;\
	EVO_TYPE *epim = NULL;\
	PIM_TYPE *ipim = NULL;\
	Kolab_conv_mail *kmail = NULL;\
	Kolab_conv_mail *kmail2 = NULL;\
	kolabconv_initialize ();\
	vcard = read_text_file_tested(args->filename);\
	epim = process_evolution_vcard_tested_##PIM_TYPE(vcard, &stage);\
	g_free(vcard);\
	ipim = process_evolution_tested_##PIM_TYPE (epim, args->validate_op, &stage);\
	free_##EVO_TYPE(epim);\
	kmail = create_kolab_tested_##PIM_TYPE (ipim, args->validate_op, &stage);\
	g_message("preconditions ok");\
	write_kolab_email_file_tested (tempfile, kmail, &stage);\
	kolabconv_free_kmail(kmail);\
	kmail2 = read_kolab_email_file_tested (tempfile, &stage);\
	ipim = process_kolab_tested_##PIM_TYPE (kmail2, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	kolabconv_free_kmail(kmail2);\
	kolabconv_shutdown ();\
}

test_convert_evolution_read_write_mailfile(EContact, I_contact)
test_convert_evolution_read_write_mailfile(ECalComponentWithTZ, I_event)
test_convert_evolution_read_write_mailfile(ECalComponentWithTZ, I_task)
test_convert_evolution_read_write_mailfile(ECalComponentWithTZ, I_note)

#define test_convert_kolab_write_mailfile(EVO_TYPE, PIM_TYPE) \
static void \
test_convert_kolab_write_mailfile_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	Kolab_conv_mail *kmail = NULL;\
	Kolab_conv_mail *kmail2 = NULL;\
	PIM_TYPE *ipim = NULL;\
	kolabconv_initialize ();\
	kmail = read_kolab_email_file_tested (args->filename, &stage);\
	g_message("preconditions ok");\
	write_kolab_email_file_tested (tempfile, kmail, &stage);\
	kolabconv_free_kmail(kmail);\
	kmail2 = read_kolab_email_file_tested (tempfile, &stage);\
	ipim = process_kolab_tested_##PIM_TYPE (kmail2, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	kolabconv_free_kmail(kmail2);\
	kolabconv_shutdown ();\
}

test_convert_kolab_write_mailfile(EContact, I_contact)
test_convert_kolab_write_mailfile(ECalComponentWithTZ, I_event)
test_convert_kolab_write_mailfile(ECalComponentWithTZ, I_task)
test_convert_kolab_write_mailfile(ECalComponentWithTZ, I_note)

#define test_convert_kolab_write_kolab(PIM_TYPE) \
static void \
test_convert_kolab_write_kolab_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	Kolab_conv_mail *kmail = NULL;\
	Kolab_conv_mail *kmail2 = NULL;\
	PIM_TYPE *ipim = NULL;\
	kolabconv_initialize ();\
	kmail = read_kolab_email_file_tested (args->filename, &stage);\
	ipim = process_kolab_tested_##PIM_TYPE (kmail, args->validate_op, &stage);\
	kolabconv_free_kmail(kmail);\
	g_message("preconditions ok");\
	kmail2 = create_kolab_tested_##PIM_TYPE (ipim, args->validate_op, &stage);\
	ipim = process_kolab_tested_##PIM_TYPE (kmail2, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	kolabconv_free_kmail(kmail2);\
	kolabconv_shutdown ();\
}

test_convert_kolab_write_kolab(I_contact)
test_convert_kolab_write_kolab(I_event)
test_convert_kolab_write_kolab(I_task)
test_convert_kolab_write_kolab(I_note)

#define test_convert_kolab_read_write_evolution(EVO_TYPE, PIM_TYPE) \
static void \
test_convert_kolab_read_write_evolution_##PIM_TYPE (const test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	Kolab_conv_mail *kmail = NULL;\
	PIM_TYPE *ipim = NULL;\
	EVO_TYPE *epim = NULL;\
	kolabconv_initialize ();\
	kmail = read_kolab_email_file_tested (args->filename, &stage);\
	ipim = process_kolab_tested_##PIM_TYPE (kmail, args->validate_op, &stage);\
	kolabconv_free_kmail(kmail);\
	g_message("preconditions ok");\
	epim = create_evolution_tested_##PIM_TYPE (ipim, args->validate_op, &stage);\
	ipim = process_evolution_tested_##PIM_TYPE (epim, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	free_##EVO_TYPE(epim);\
	kolabconv_shutdown ();\
}

test_convert_kolab_read_write_evolution(EContact, I_contact)
test_convert_kolab_read_write_evolution(ECalComponentWithTZ, I_event)
test_convert_kolab_read_write_evolution(ECalComponentWithTZ, I_task)
test_convert_kolab_read_write_evolution(ECalComponentWithTZ, I_note)

#define test_convert_kolab_read_write_vcard(EVO_TYPE, PIM_TYPE) \
static void \
test_convert_kolab_read_write_vcard_##PIM_TYPE (test_args_##PIM_TYPE *args)\
{\
	gint stage = 0;\
	gchar *vcard_str = NULL;\
	Kolab_conv_mail *kmail = NULL;\
	PIM_TYPE *ipim = NULL;\
	EVO_TYPE *econtact = NULL;\
	EVO_TYPE *econtact2 = NULL;\
	kolabconv_initialize ();\
	kmail = read_kolab_email_file_tested (args->filename, &stage);\
	ipim = process_kolab_tested_##PIM_TYPE (kmail, args->validate_op, &stage);\
	kolabconv_free_kmail(kmail);\
	econtact = create_evolution_tested_##PIM_TYPE (ipim, args->validate_op, &stage);\
	g_message("preconditions ok");\
	vcard_str = create_evolution_vcard_tested_##PIM_TYPE(econtact, &stage);\
	free_##EVO_TYPE(econtact);\
	g_debug("VCard:\n%s", vcard_str);\
	econtact2 = process_evolution_vcard_tested_##PIM_TYPE(vcard_str, &stage);\
	g_free(vcard_str);\
	ipim = process_evolution_tested_##PIM_TYPE (econtact2, args->validate_op, &stage);\
	free_##PIM_TYPE(&ipim);\
	free_##EVO_TYPE(econtact2);\
	kolabconv_shutdown ();\
}

test_convert_kolab_read_write_vcard(EContact, I_contact)
test_convert_kolab_read_write_vcard(ECalComponentWithTZ, I_event)
test_convert_kolab_read_write_vcard(ECalComponentWithTZ, I_task)
test_convert_kolab_read_write_vcard(ECalComponentWithTZ, I_note)

/**
 * Returns the current working directory. This should be the root path of the
 * project evolution-kolab.
 *
 * @return The current working directory
 */
static gchar*
get_working_dir (void)
{
	gchar *path1 = g_new0(gchar, MAXPATHLEN); /* This is a buffer for the text */
	getcwd (path1, MAXPATHLEN);
	return path1;
}

static gchar*
create_test_name(gchar *format, gchar *name)
{
	gchar *ret = g_strdup_printf (format, name);
	free_after_test(ret);
	return ret;
}

/**
 * Adds some conversion tests for a kolab contact file which is given by the uid
 * parameter. The given validation operation is used to test if the conversions
 * are working correctly.
 *
 * @param  uid
 *         a uid of a kolab contact mail file
 * @param  validate_op
 *         an operation which tests if the internal contact structure contains
 *         the informations which are hold in the kolab contact mail
 */
#define add_tests_kolab(PIM_TYPE) \
static void \
add_tests_kolab_##PIM_TYPE (gchar *filename, void (*validate_op) (const PIM_TYPE*, int)) \
{\
	test_args_##PIM_TYPE *args = NULL;\
	/* create the absolute filename of the contact with the given uid */\
	gchar *kolab_file_rel = g_strdup_printf("%s%s",\
			kolab_folder_##PIM_TYPE, filename);\
	gchar *working_dir = get_working_dir ();\
	gchar *kolab_file_name = g_strdup_printf("%s/%s%s",\
			working_dir, test_resource_folder, kolab_file_rel);\
	\
	/* put filename and validating operation in an argument struct to be passed to the test operations */\
	args = g_new0(test_args_##PIM_TYPE, 1);\
	args-> filename = kolab_file_name;\
	args-> validate_op = validate_op;\
	\
	/* add some tests for each contact */\
	g_test_add_data_func (\
			create_test_name("/convert/%s/read_mailfile_read_kolab", kolab_file_rel),\
			args, (gconstpointer) test_convert_kolab_read_mailfile_read_kolab_##PIM_TYPE);\
	g_test_add_data_func (\
			create_test_name("/convert/%s/write_kolab", kolab_file_rel),\
			args, (gconstpointer) test_convert_kolab_write_kolab_##PIM_TYPE);\
	g_test_add_data_func (\
			create_test_name("/convert/%s/read_write_evolution", kolab_file_rel),\
			args, (gconstpointer) test_convert_kolab_read_write_evolution_##PIM_TYPE);\
	g_test_add_data_func (\
			create_test_name("/convert/%s/read_write_vcard", kolab_file_rel),\
			args, (gconstpointer) test_convert_kolab_read_write_vcard_##PIM_TYPE);\
	g_test_add_data_func (\
			create_test_name("/convert/%s/write_mailfile", kolab_file_rel),\
			args, (gconstpointer) test_convert_kolab_write_mailfile_##PIM_TYPE);\
	/* clean resources after tests are done */\
	free(working_dir);\
	free_after_test(kolab_file_rel);\
	free_after_test(kolab_file_name);\
	free_after_test(args);\
}

add_tests_kolab(I_contact)
add_tests_kolab(I_event)
add_tests_kolab(I_task)
add_tests_kolab(I_note)

#define add_tests_evolution(PIM_TYPE) \
static void \
add_tests_evolution_##PIM_TYPE (gchar *filename, void (*validate_op) (const PIM_TYPE*, int))\
{\
	test_args_##PIM_TYPE *args = NULL;\
	/* create the absolute filename of the contact with the given uid */\
	gchar *kolab_file_rel = g_strdup_printf("%s%s",\
			evolution_folder_##PIM_TYPE, filename);\
	gchar *working_dir = get_working_dir ();\
	gchar *kolab_file_name = g_strdup_printf("%s/%s%s",\
			working_dir, test_resource_folder, kolab_file_rel);\
	\
	/* put filename and validating operation in an argument struct to be passed to the test operations */\
	args = g_new0(test_args_##PIM_TYPE, 1);\
	args-> filename = kolab_file_name;\
	args-> validate_op = validate_op;\
	\
	/* add some tests for each contact */\
	g_test_add_data_func (\
			create_test_name("/convert/%s/read_vcard_read_evolution", kolab_file_rel),\
			args, (gconstpointer) test_convert_evolution_read_vcard_read_evolution_##PIM_TYPE);\
	g_test_add_data_func (\
			create_test_name("/convert/%s/write_evolution", kolab_file_rel),\
			args, (gconstpointer) test_convert_evolution_write_evolution_##PIM_TYPE);\
	g_test_add_data_func (\
			create_test_name("/convert/%s/read_write_kolab", kolab_file_rel),\
			args, (gconstpointer) test_convert_evolution_read_write_kolab_##PIM_TYPE);\
	g_test_add_data_func (\
			create_test_name("/convert/%s/read_write_mailfile", kolab_file_rel),\
			args, (gconstpointer) test_convert_evolution_read_write_mailfile_##PIM_TYPE);\
	g_test_add_data_func (\
			create_test_name("/convert/%s/write_vcard", kolab_file_rel),\
			args, (gconstpointer) test_convert_evolution_write_vcard_##PIM_TYPE);\
	/* clean resources after tests are done */\
	free(working_dir);\
	free_after_test(kolab_file_rel);\
	free_after_test(kolab_file_name);\
	free_after_test(args);\
}

add_tests_evolution(I_contact)
add_tests_evolution(I_event)
add_tests_evolution(I_task)
add_tests_evolution(I_note)


#define add_all_tests(PIM_TYPE) \
void \
add_all_tests_##PIM_TYPE(void)\
{\
	/* add kolab contact tests */\
	/* get number of contact tests */\
	int i, length = sizeof(test_k_##PIM_TYPE) / sizeof(process_pim_type(PIM_TYPE));\
	/* add some tests for each contact */\
	for (i = 0; i < length; i++)\
		add_tests_kolab_##PIM_TYPE (test_k_##PIM_TYPE[i].filename, test_k_##PIM_TYPE[i].validate_op);\
	\
	/* add evolution contact tests */\
	/* get number of contact tests */\
	length = sizeof(test_e_##PIM_TYPE) / sizeof(process_pim_type(PIM_TYPE));\
	/* add some tests for each contact */\
	for (i = 0; i < length; i++)\
		add_tests_evolution_##PIM_TYPE (test_e_##PIM_TYPE[i].filename, test_e_##PIM_TYPE[i].validate_op);\
}

add_all_tests(I_contact)
add_all_tests(I_event)
add_all_tests(I_task)
add_all_tests(I_note)
