/*
 * libsyncml - A syncml protocol implementation
 * Copyright (C) 2005  Armin Bauer <armin.bauer@opensync.org>
 * Copyright (C) 2008-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/parser/sml_wbxml_internals.h>

#include <libsyncml/sml_command_internals.h>
#include <libsyncml/sml_elements_internals.h>
#include <libsyncml/data_sync_api/sml_location.h>
#include <libsyncml/data_sync_api/sml_data_sync_defines.h>
#include <libsyncml/sml_error_internals.h>

static SmlAssembler *start_assembler(SmlSession *session, unsigned int limit)
{
	GError *error = NULL;

	SmlAssembler *assm = smlAssemblerNew(SML_MIMETYPE_WBXML, limit, &error);
	sml_fail_unless(assm != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	if (!smlAssemblerStart(assm, session, &error)) {
		sml_fail_unless(error != NULL, NULL);
		smlAssemblerFree(assm);
		return NULL;
	}
	return assm;
}

START_TEST (wbxml_assembler_message_empty)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);
	g_object_unref(loc);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_message_only_header)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);
	g_object_unref(loc);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_message_status)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);
	g_object_unref(loc);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerReserveStatus(assm, 1, 1, 1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlStatus *status = smlStatusNew(SML_NO_ERROR, 1, 1, loc, loc, SML_COMMAND_TYPE_SYNC, &error);
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddStatus(assm, status, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);

	smlStatusUnref(status);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_message_cmd)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd = smlCommandNewAlert(SML_ALERT_TWO_WAY, loc, loc, "next", "last", NULL, &error);
	sml_fail_unless(cmd != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd->cmdID = 1;
	g_object_unref(loc);
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);

	smlCommandUnref(cmd);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	
	char *buffer = NULL;
	size_t buffer_size = 0;
	sml_fail_unless(smlWbxmlConvertFrom(NULL, data, size, &buffer, &buffer_size, &error), NULL);
	sml_fail_unless(buffer != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	smlSafeCFree(&data);
	smlSafeCFree(&buffer);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_message_subcmd)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd1 = smlCommandNewSync(loc, loc, 0, &error);
	sml_fail_unless(cmd1 != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd1->cmdID = 1;
	g_object_unref(loc);
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd2 = NULL;
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	sml_fail_unless(cmd2 != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd2->cmdID = 2;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd1);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_message_several_subcmd)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd1 = smlCommandNewSync(loc, loc, 0, &error);
	sml_fail_unless(cmd1 != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd1->cmdID = 1;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd2 = NULL;
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 2;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid2", "data2", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 3;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd1);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	cmd1 = smlCommandNewSync(loc, loc, 0, &error);
	sml_fail_unless(cmd1 != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd1->cmdID = 4;
	g_object_unref(loc);
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 5;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid2", "data2", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 6;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd1);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_message_flush_open)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd1 = smlCommandNewSync(loc, loc, 0, &error);
	sml_fail_unless(cmd1 != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd1->cmdID = 1;
	g_object_unref(loc);
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd2 = NULL;
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 2;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, FALSE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid2", "data2", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 3;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd1);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_out_of_order)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd1 = smlCommandNewSync(loc, loc, 0, &error);
	sml_fail_unless(cmd1 != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd1->cmdID = 1;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlCommand *cmd2 = NULL;
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 2;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	SmlCommand *cmd3 = smlCommandNewSync(loc, loc, 0, &error);
	sml_fail_unless(cmd3 != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd3->cmdID = 4;
	g_object_unref(loc);
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd3, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 5;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd3, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd3, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid2", "data2", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 3;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd1, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid2", "data2", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 6;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd3, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd3, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid2", "data2", 5, SML_ELEMENT_TEXT_VCARD);
	cmd2 = smlCommandNewChange(TEST_DATA_SYNC_CHANGE_ITEM, &error);
	TEST_DATA_SYNC_CHANGE_ITEM_FREE();
	cmd2->cmdID = 7;
	
	sml_fail_unless(smlAssemblerStartCommand(assm, cmd3, cmd2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, cmd3, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd2);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd1);
	smlCommandUnref(cmd3);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_limit1)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 1);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(!smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_limit2)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 50);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(!smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_limit3)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 100);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerReserveStatus(assm, 1, 1, 1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlStatus *status = smlStatusNew(SML_NO_ERROR, 1, 1, loc, loc, SML_COMMAND_TYPE_SYNC, &error);
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddStatus(assm, status, &error) == SML_ASSEMBLER_RESULT_MISMATCH, NULL);
	sml_fail_unless(error == NULL, NULL);

	smlStatusUnref(status);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(!smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error != NULL, NULL);
	SML_ERROR_FREE(error);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_limit4)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 380);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerReserveStatus(assm, 1, 1, 1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlStatus *status = smlStatusNew(SML_NO_ERROR, 1, 1, loc, loc, SML_COMMAND_TYPE_SYNC, &error);
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddStatus(assm, status, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);

	smlStatusUnref(status);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlSafeCFree(&data);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_limit5)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 150);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerReserveStatus(assm, 1, 1, 1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlStatus *status = smlStatusNew(SML_NO_ERROR, 1, 1, loc, loc, SML_COMMAND_TYPE_SYNC, &error);
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddStatus(assm, status, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);

	smlStatusUnref(status);
	
	SmlCommand *cmd = smlCommandNewAlert(SML_ALERT_TWO_WAY, loc, loc, "next", "last", NULL, &error);
	sml_fail_unless(cmd != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd->cmdID = 1;
	g_object_unref(loc);
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd, &error) == SML_ASSEMBLER_RESULT_MISMATCH, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, FALSE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);

	smlCommandUnref(cmd);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

START_TEST (wbxml_assembler_complex1)
{
	setup_testbed(NULL);
	GError *error = NULL;
	
	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "/test");
	
	/* The session type must be SML_SESSION_TYPE_CLIENT
	 * because servers of SyncML 1.1 or higher must send MaxMsgSize.
	 */
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 1, 0, &error);

	SmlAssembler *assm = start_assembler(session, 0);
	sml_fail_unless(assm != NULL, NULL);
	
	sml_fail_unless(smlAssemblerReserveStatus(assm, 1, 1, 1, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlAssemblerReserveStatus(assm, 2, 1, 2, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlAssemblerReserveStatus(assm, 3, 1, 3, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlAssemblerReserveStatus(assm, 4, 1, 4, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddHeader(assm, session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlStatus *status = smlStatusNew(SML_NO_ERROR, 1, 1, loc, loc, SML_COMMAND_TYPE_SYNC, &error);
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddStatus(assm, status, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);
	smlStatusUnref(status);
	
	status = smlStatusNew(SML_NO_ERROR, 2, 1, loc, loc, SML_COMMAND_TYPE_SYNC, &error);
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddStatus(assm, status, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);
	smlStatusUnref(status);
	
	status = smlStatusNew(SML_NO_ERROR, 3, 1, loc, loc, SML_COMMAND_TYPE_SYNC, &error);
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddStatus(assm, status, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);
	smlStatusUnref(status);
	
	status = smlStatusNew(SML_NO_ERROR, 4, 1, loc, loc, SML_COMMAND_TYPE_SYNC, &error);
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlAssemblerAddStatus(assm, status, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);
	smlStatusUnref(status);
	
	SmlCommand *cmd = smlCommandNewAlert(SML_ALERT_TWO_WAY, loc, loc, "next", "last", NULL, &error);
	sml_fail_unless(cmd != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	cmd->cmdID = 5;
	g_object_unref(loc);
	
	sml_fail_unless(smlAssemblerStartCommand(assm, NULL, cmd, &error) == SML_ASSEMBLER_RESULT_OK, NULL);
	sml_fail_unless(error == NULL, NULL);
	smlCommandUnref(cmd);
	
	sml_fail_unless(smlAssemblerEndCommand(assm, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	char *data = NULL;
	gsize size = 0;
	sml_fail_unless(smlAssemblerRun(assm, &data, &size, NULL, FALSE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(data != NULL, NULL);
	sml_fail_unless(size != 0, NULL);
	smlSafeCFree(&data);
	
	sml_fail_unless(smlAssemblerFlush(assm) == 1, NULL);
	sml_fail_unless(error == NULL, NULL);
	
	smlAssemblerFree(assm);
	smlSessionUnref(session);
}
END_TEST

@SML_TESTCASE_CODE@

