/*
 * libsyncml - A syncml protocol implementation
 * Copyright (C) 2009  Michael Bell <michael.bell@opensync.org>
 *
 * 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
 *
 */
 
#include "tests/support.h"

#include <libsyncml/data_sync_api/sml_data_sync_change_item_internals.h>
#include <string.h>

START_TEST (change_item_new)
{
	setup_testbed(NULL);
	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_location)
{
	setup_testbed(NULL);

	GError *error = NULL;
	SmlLocation *location = sml_location_new();
	sml_fail_unless(location != NULL, NULL);
	sml_location_set_uri(location, "1234");

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_set_location(item, location, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_unref(location);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_location_null)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_set_location(item, NULL, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_location_missing_uri)
{
	setup_testbed(NULL);

	GError *error = NULL;
	SmlLocation *location = sml_location_new();
	sml_fail_unless(location != NULL, NULL);

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(!sml_data_sync_change_item_set_location(item, location, &error), "The location must have an URI.");
	sml_fail_unless(error != NULL, NULL);

	g_error_free(error);
	g_object_unref(location);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_location)
{
	setup_testbed(NULL);

	GError *error = NULL;
	SmlLocation *location = sml_location_new();
	sml_fail_unless(location != NULL, NULL);
	sml_location_set_uri(location, "1234");

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_location(item) == NULL, "The location is not set until now.");

	sml_fail_unless(sml_data_sync_change_item_set_location(item, location, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_location(item) != NULL, "The location must be set now.");
	sml_fail_unless(sml_data_sync_change_item_get_location(item) == location, "The location must be 1234.");

	sml_fail_unless(sml_data_sync_change_item_set_location(item, NULL, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_location(item) == NULL, "The location was deleted.");

	g_object_unref(location);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_data)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	const gchar* data = "I am a vCard.";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_data_with_limit)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	const gchar* data = "I am a vCard.";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, strlen(data)-3, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_data_with_length)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	const gchar* data = "I am a vCard.";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, strlen(data), &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_data_with_overflow)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	const gchar* data = "I am a vCard.";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, strlen(data)+3, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_data_not_null)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(!sml_data_sync_change_item_set_data(item, NULL, 0, &error), "There must be some data.");
	sml_fail_unless(error != NULL, NULL);

	g_error_free(error);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_data)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_data(item) == NULL, NULL);

	const gchar* data = "I am a vCard.";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	const char* result = sml_data_sync_change_item_get_data(item);
	sml_fail_unless(result !=  NULL, "The data must be present.");
	sml_fail_unless(strcmp(result, data) == 0, "The data must be '%s'.", result);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_data_with_limit)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_data(item) == NULL, NULL);

	const gchar* data = "I am a vCard.";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, strlen(data)-3, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	const char* result = sml_data_sync_change_item_get_data(item);
	sml_fail_unless(result !=  NULL, "The data must be present.");
	sml_fail_unless(strlen(data)-3 == strlen(result), "The data has the wrong length.");
	sml_fail_unless(strncmp(result, data, strlen(data)-3) == 0, "The data must be a part from '%s'.", result);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_data_with_length)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_data(item) == NULL, NULL);

	const gchar* data = "I am a vCard.";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, strlen(data), &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	const char* result = sml_data_sync_change_item_get_data(item);
	sml_fail_unless(result !=  NULL, "The data must be present.");
	sml_fail_unless(strcmp(result, data) == 0, "The data must be '%s'.", result);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_data_with_overflow)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_data(item) == NULL, NULL);

	const gchar* data = "I am a vCard.";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, strlen(data)+3, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	const char* result = sml_data_sync_change_item_get_data(item);
	sml_fail_unless(result !=  NULL, "The data must be present.");
	sml_fail_unless(strcmp(result, data) == 0, "The data must be '%s'.", result);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_binary_data)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	const gchar* data = "I am an image.";
	sml_fail_unless(sml_data_sync_change_item_set_binary_data(item, data, strlen(data), &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_binary_data)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_data(item) == NULL, NULL);

	const gchar* data = "I am an image.";
	const gchar* encoded = "SSBhbSBhbiBpbWFnZS4=";
	sml_fail_unless(sml_data_sync_change_item_set_binary_data(item, data, strlen(data), &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	const char* result = sml_data_sync_change_item_get_data(item);
	sml_fail_unless(result !=  NULL, "The data must be present.");
	sml_fail_unless(strcmp(result, encoded) == 0, "The encoded data must be '%s' and not '%s'.", encoded, result);

	gchar* binary = NULL;
	gsize size = 0;
	sml_fail_unless(sml_data_sync_change_item_get_binary_data(item, &binary, &size, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(binary !=  NULL, "The binary data must be present.");
	sml_fail_unless(size == strlen(data), "The decoded data has a different length then the original.");
	sml_fail_unless(strcmp(binary, data) == 0, "The decoced data must be '%s' and not '%s'.", data, binary);
	smlSafeCFree(&binary);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_planned_size)
{
	setup_testbed(NULL);

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_data_sync_change_item_set_planned_size(item, 0);
	sml_data_sync_change_item_set_planned_size(item, 1);
	sml_data_sync_change_item_set_planned_size(item, 2);
	sml_data_sync_change_item_set_planned_size(item, 0);
	sml_data_sync_change_item_set_planned_size(item, 1);
	sml_data_sync_change_item_set_planned_size(item, 0);
	sml_data_sync_change_item_set_planned_size(item, 2);
	sml_data_sync_change_item_set_planned_size(item, 2);
	sml_data_sync_change_item_set_planned_size(item, 0);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_planned_size)
{
	setup_testbed(NULL);

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 0, NULL);
	sml_data_sync_change_item_set_planned_size(item, 0);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 0, NULL);
	sml_data_sync_change_item_set_planned_size(item, 1);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 1, NULL);
	sml_data_sync_change_item_set_planned_size(item, 2);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 2, NULL);
	sml_data_sync_change_item_set_planned_size(item, 0);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 0, NULL);
	sml_data_sync_change_item_set_planned_size(item, 1);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 1, NULL);
	sml_data_sync_change_item_set_planned_size(item, 0);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 0, NULL);
	sml_data_sync_change_item_set_planned_size(item, 2);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 2, NULL);
	sml_data_sync_change_item_set_planned_size(item, 2);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 2, NULL);
	sml_data_sync_change_item_set_planned_size(item, 0);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(item) == 0, NULL);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_content_type)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_set_content_type(item, "text/plain", &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_set_content_type(item, "text/html", &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_set_content_type_not_null)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(!sml_data_sync_change_item_set_content_type(item, NULL, &error), NULL);
	sml_fail_unless(error != NULL, NULL);

	g_error_free(error);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_content_type)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_get_content_type(item) == NULL, "The default content-type is NULL.");

	sml_fail_unless(sml_data_sync_change_item_set_content_type(item, "text/plain", &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	const char* result = sml_data_sync_change_item_get_content_type(item);
	sml_fail_unless(result != NULL, "The content-type is present.");
	sml_fail_unless(strcmp(result, "text/plain") == 0, "The content-type must be text/plain.");

	sml_fail_unless(sml_data_sync_change_item_set_content_type(item, "text/html", &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	result = sml_data_sync_change_item_get_content_type(item);
	sml_fail_unless(result != NULL, "The content-type is present.");
	sml_fail_unless(strcmp(result, "text/html") == 0, "The content-type must be text/html.");

	sml_fail_unless(!sml_data_sync_change_item_set_content_type(item, NULL, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	g_error_free(error);
	error = NULL;
	result = sml_data_sync_change_item_get_content_type(item);
	sml_fail_unless(result != NULL, "The content-type is present.");
	sml_fail_unless(strcmp(result, "text/html") == 0, "The content-type must be text/html.");

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_fragment_missing_data)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();

	sml_fail_unless(!sml_data_sync_change_item_get_fragment(item, 0, 10, &error), "Fragmentation on empty items is not supported.");
	sml_fail_unless(error != NULL, NULL);

	g_error_free(error);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_fragment)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();

	const gchar* data = "1234567890abcdefghijklmnopqrstuvwxyz";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	/* get the first chunk */

	SmlDataSyncChangeItem *frag = sml_data_sync_change_item_get_fragment(item, 0, 10, &error);
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_location(frag) == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_content_type(frag) == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_missing_data(frag) == TRUE, NULL);
	/* only the first element contains the size */
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(frag) == strlen(data), NULL);
	sml_fail_unless(sml_data_sync_change_item_get_data(frag) != NULL, NULL);
	sml_fail_unless(strcmp("1234567890", sml_data_sync_change_item_get_data(frag)) == 0, NULL);
	g_object_unref(frag);
	frag = NULL;

	/* set location and content-type */

	SmlLocation *location = sml_location_new();
	sml_fail_unless(location != NULL, NULL);
	sml_location_set_uri(location, "1234");

	sml_fail_unless(sml_data_sync_change_item_set_location(item, location, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_set_content_type(item, "text/plain", &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	/* get the next chunk with location and content-type */

	frag = sml_data_sync_change_item_get_fragment(item, 10, 10, &error);
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_location(frag) == location, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_content_type(frag) != NULL, NULL);
	sml_fail_unless(strcmp(sml_data_sync_change_item_get_content_type(frag), "text/plain") == 0, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_missing_data(frag) == TRUE, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(frag) == 0, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_data(frag) != NULL, NULL);
	sml_fail_unless(strcmp("abcdefghij", sml_data_sync_change_item_get_data(frag)) == 0, NULL);
	g_object_unref(frag);

	/* get last chunk */

	frag = sml_data_sync_change_item_get_fragment(item, 20, 16, &error);
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_location(frag) == location, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_content_type(frag) != NULL, NULL);
	sml_fail_unless(strcmp(sml_data_sync_change_item_get_content_type(frag), "text/plain") == 0, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_missing_data(frag) == FALSE, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(frag) == 0, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_data(frag) != NULL, NULL);
	sml_fail_unless(strcmp("klmnopqrstuvwxyz", sml_data_sync_change_item_get_data(frag)) == 0, NULL);
	g_object_unref(frag);

	g_object_unref(location);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_too_large_fragment)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();

	const gchar* data = "1234567890abcdefghijklmnopqrstuvwxyz";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	/* get the first chunk */

	SmlDataSyncChangeItem *frag = sml_data_sync_change_item_get_fragment(item, 0, strlen(data)+1, &error);
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_location(frag) == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_content_type(frag) == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_missing_data(frag) == FALSE, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_planned_size(frag) == 0, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_data(frag) != NULL, NULL);
	sml_fail_unless(strcmp(data, sml_data_sync_change_item_get_data(frag)) == 0, NULL);
	g_object_unref(frag);
	frag = NULL;

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_get_illegal_fragment)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();

	const gchar* data = "1234567890abcdefghijklmnopqrstuvwxyz";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	/* get the first chunk */

	sml_fail_unless(!sml_data_sync_change_item_get_fragment(item, strlen(data), 10, &error), "The fragment start position is too large.");
	sml_fail_unless(error != NULL, NULL);
	g_error_free(error);

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_attach_empty_fragment)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	SmlDataSyncChangeItem *frag = sml_data_sync_change_item_new();

	sml_fail_unless(!sml_data_sync_change_item_attach_fragment(item, NULL, &error), "A fragment cannot be empty.");
	sml_fail_unless(error != NULL, NULL);
	g_error_free(error);
	error = NULL;

	sml_fail_unless(!sml_data_sync_change_item_attach_fragment(item, frag, &error), "A fragment cannot be empty.");
	sml_fail_unless(error != NULL, NULL);
	g_error_free(error);
	error = NULL;

	g_object_unref(frag);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_attach_fragment)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();

	const gchar* data1 = "1234567890";
	const gchar* data2 = "abcdefghij";
	const gchar* data3 = "klmnopqrstuvwxyz";

	sml_data_sync_change_item_set_planned_size(item, strlen(data1) + strlen(data2) + strlen(data3));
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data1, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_data_sync_change_item_set_missing_data(item, TRUE);

	/* add the first chunk */

	SmlDataSyncChangeItem *frag = sml_data_sync_change_item_new();
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(sml_data_sync_change_item_set_data(frag, data2, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_data_sync_change_item_set_missing_data(frag, TRUE);

	sml_fail_unless(sml_data_sync_change_item_attach_fragment(item, frag, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(strlen(sml_data_sync_change_item_get_data(item)) == strlen(data1) + strlen(data2), NULL);
	sml_fail_unless(sml_data_sync_change_item_get_missing_data(item) == TRUE, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_location(item) == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_content_type(item) == NULL, NULL);
	g_object_unref(frag);
	frag = NULL;

	/* set location and content-type */

	SmlLocation *location = sml_location_new();
	sml_fail_unless(location != NULL, NULL);
	sml_location_set_uri(location, "1234");

	sml_fail_unless(sml_data_sync_change_item_set_location(item, location, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_set_content_type(item, "text/plain", &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	/* add the last chunk with location and content-type */

	frag = sml_data_sync_change_item_new();
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(sml_data_sync_change_item_set_data(frag, data3, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_data_sync_change_item_set_missing_data(frag, FALSE);
	sml_fail_unless(sml_data_sync_change_item_set_location(frag, location, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_set_content_type(frag, "text/plain", &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_attach_fragment(item, frag, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(strlen(sml_data_sync_change_item_get_data(item)) == strlen(data1) + strlen(data2) + strlen(data3), NULL);
	sml_fail_unless(sml_data_sync_change_item_get_missing_data(item) == FALSE, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_location(item) == location, NULL);
	sml_fail_unless(strcmp(sml_data_sync_change_item_get_content_type(item), "text/plain") == 0, NULL);
	g_object_unref(frag);
	frag = NULL;

	g_object_unref(location);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_attach_too_long_fragment)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();

	const gchar* data1 = "1234567890";
	const gchar* data3 = "klmnopqrstuvwxyz";
	const gchar* datak = "klmnopqrstuvwxyzABC";

	sml_data_sync_change_item_set_planned_size(item, strlen(data1) + strlen(data3));
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data1, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_data_sync_change_item_set_missing_data(item, TRUE);

	/* add the too large chunk */

	SmlDataSyncChangeItem *frag = sml_data_sync_change_item_new();
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(sml_data_sync_change_item_set_data(frag, datak, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_data_sync_change_item_set_missing_data(frag, FALSE);

	sml_fail_unless(!sml_data_sync_change_item_attach_fragment(item, frag, &error), "The fragment is larger then the planned size.");
	sml_fail_unless(error != NULL, NULL);

	g_error_free(error);
	g_object_unref(frag);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_attach_unnecessary_fragment)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();

	const gchar* data1 = "1234567890";
	const gchar* data2 = "abcdefghij";
	const gchar* data3 = "klmnopqrstuvwxyz";

	sml_data_sync_change_item_set_planned_size(item, strlen(data1) + strlen(data2));
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data1, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_data_sync_change_item_set_missing_data(item, TRUE);

	/* add the first and last chunk */

	SmlDataSyncChangeItem *frag = sml_data_sync_change_item_new();
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(sml_data_sync_change_item_set_data(frag, data2, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_data_sync_change_item_set_missing_data(frag, FALSE);

	sml_fail_unless(sml_data_sync_change_item_attach_fragment(item, frag, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(strlen(sml_data_sync_change_item_get_data(item)) == strlen(data1) + strlen(data2), NULL);
	sml_fail_unless(sml_data_sync_change_item_get_missing_data(item) == FALSE, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_location(item) == NULL, NULL);
	sml_fail_unless(sml_data_sync_change_item_get_content_type(item) == NULL, NULL);
	g_object_unref(frag);
	frag = NULL;

	/* add the unnecessary chunk */

	frag = sml_data_sync_change_item_new();
	sml_fail_unless(frag != NULL, "%s", error?error->message:"No GError set.");
	sml_fail_unless(sml_data_sync_change_item_set_data(frag, data3, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_data_sync_change_item_set_missing_data(frag, FALSE);

	sml_fail_unless(!sml_data_sync_change_item_attach_fragment(item, frag, &error), "The chunk is not necessary.");
	sml_fail_unless(error != NULL, NULL);

	g_error_free(error);
	g_object_unref(frag);
	g_object_unref(item);
}
END_TEST

START_TEST (change_item_data_fix_cr)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	const gchar* data = "1\r2";
	const gchar* result = "1\n2";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) == strlen(sml_data_sync_change_item_get_data(item)), "The length should not change during CR replacement.");
	sml_fail_unless(!strcmp(result, sml_data_sync_change_item_get_data(item)), "CR must be replaced by LF.");

	data = "1\r2\r3\r4";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) == strlen(sml_data_sync_change_item_get_data(item)), "CRs must be replaced by LFs.");

	data = "1\r2\r3\r4\r";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) == strlen(sml_data_sync_change_item_get_data(item)), "CRs even at the end must be replaced by LFs.");

	data = "1\r2\r\r\r3\r4";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) == strlen(sml_data_sync_change_item_get_data(item)), "CRs must be replaced by LFs.");

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_data_fix_crlf)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	const gchar* data = "1\r\n2";
	const gchar* result = "1\n2";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) -1 == strlen(sml_data_sync_change_item_get_data(item)), "One CRLF must be replaced by LF (%d != %d).", strlen(data) -1, strlen(sml_data_sync_change_item_get_data(item)));
	sml_fail_unless(!strcmp(result, sml_data_sync_change_item_get_data(item)), "CRLF must be replaced by LF.");

	data = "1\r\n2\r\n3\r\n4";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) -3 == strlen(sml_data_sync_change_item_get_data(item)), "CRLFs must be replaced by LFs.");

	data = "1\r\n2\r\n3\r\n4\r\n";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) -4 == strlen(sml_data_sync_change_item_get_data(item)), "CRLFs even at the end must be replaced by LFs.");

	data = "1\r\n2\r\n\r\n\r\n3\r\n4";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) -5 == strlen(sml_data_sync_change_item_get_data(item)), "CRLFs must be replaced by LFs.");

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_data_fix_cr_and_crlf)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	const gchar* data = "1\r2\r\n3\r\r\n4\r\n\r5";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) -3 == strlen(sml_data_sync_change_item_get_data(item)), "CRLF must be replaced by LF.");

	data = "1\r\n\r";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) -1 == strlen(sml_data_sync_change_item_get_data(item)), "CRLF must be replaced by LF.");

	data = "1\r\r\n";
	sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(strlen(data) -1 == strlen(sml_data_sync_change_item_get_data(item)), "CRLF must be replaced by LF.");

	g_object_unref(item);
}
END_TEST

START_TEST (change_item_references)
{
	setup_testbed(NULL);

	GError *error = NULL;

	SmlDataSyncChangeItem *item = sml_data_sync_change_item_new();
	sml_fail_unless(item != NULL, NULL);

	sml_fail_unless(sml_data_sync_change_item_set_data(item, "1234", 0, &error), "%s", error?error->message:"No GError set.");
	sml_fail_unless(error == NULL, NULL);

	g_object_ref(item);

	sml_fail_unless(sml_data_sync_change_item_get_data(item) != NULL, "The data was not set.");

	g_object_unref(item);

	sml_fail_unless(sml_data_sync_change_item_get_data(item) != NULL, "The data is already cleaned up.");

	g_object_unref(item);
}
END_TEST

@SML_TESTCASE_CODE@

