Revision 13 (by moose, 2008/11/12 09:27:00) * add testing framework
* fix encoding/decoding bugs
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>

#include "cseproto/cseproto.h"
#include "cseproto/cseproto_encode.h"

char *current_test = NULL;

#define mylog(a,b,c...) \
	do { \
		char __log_tmp__[1024]; \
		snprintf(__log_tmp__, 1024, b,##c); \
		fprintf(stderr, "%s:%s:%i %s: %s: %s\n", __FILE__, __FUNCTION__, __LINE__, current_test, a, __log_tmp__); \
	} while(0)

#define err(b,c...) \
	do { \
		mylog("ERROR",b,##c); \
		exit(EXIT_FAILURE); \
	} while(0)

int test1(char *arg)
{
	cseproto_t *msg = NULL, *decoded = NULL;
	cseproto_item_t *varint_item = NULL;
	uint64_t varint = 0xDECAF;
	cseproto_item_t *svarint_item = NULL;
	int64_t svarint = 0xDEADBEEFDECAFBADLL;
	cseproto_item_t *fixed32_item = NULL;
	uint32_t fixed32 = 0xDEADBEEF;
	cseproto_item_t *fixed64_item = NULL;
	uint64_t fixed64 = 0xDEADBEEFDECAFBADLL;
	cseproto_item_t *float32_item = NULL;
	float float32 = 1.23456789;
	cseproto_item_t *float64_item = NULL;
	double float64 = 1.23456789;
	cseproto_item_t *string_item = NULL;
	char *string = "this is a test 2";
	uint8_t *encoded_data = NULL;
	size_t encoded_data_len = 0, decoded_data_len = 0;
	uint32_t i = 0;
	FILE *fh = NULL;
	
	msg =  cseproto_create(7);
	//mylog("LOG", "buckets: %i", msg->bucket_count);
	if(!msg)
		err("failed to create cseproto struct");

	//mylog("LOG", "buckets: %i", msg->bucket_count);
	
	varint_item  = cseproto_create_item(0, CSE_WIRETYPE_VARINT,   sizeof(varint), &varint);
	if(!varint_item)
		err("failed to create varint item");

	if(!cseproto_add_item(msg, varint_item))
		err("failed to add varint item to message");
	
	svarint_item = cseproto_create_item(1, CSE_WIRETYPE_SVARINT,  sizeof(svarint), &svarint);
	if(!svarint_item)
		err("failed to create svarint item");

	if(!cseproto_add_item(msg, svarint_item))
		err("failed to add svarint item to message");
	
	fixed32_item = cseproto_create_item(2, CSE_WIRETYPE_32BIT,    sizeof(fixed32), &fixed32);
	if(!fixed32_item)
		err("failed to create fixed32 item");

	if(!cseproto_add_item(msg, fixed32_item))
		err("failed to add fixed32 item to message");
	
	fixed64_item = cseproto_create_item(3, CSE_WIRETYPE_64BIT,    sizeof(fixed64), &fixed64);
	if(!fixed64_item)
		err("failed to create fixed64 item");

	if(!cseproto_add_item(msg, fixed64_item))
		err("failed to add fixed64 item to message");
	
	float32_item = cseproto_create_item(4, CSE_WIRETYPE_32BIT,    sizeof(float32), &float32);
	if(!float32_item)
		err("failed to create float32 item");

	if(!cseproto_add_item(msg, float32_item))
		err("failed to add float32 item to message");
	
	float64_item = cseproto_create_item(5, CSE_WIRETYPE_64BIT,    sizeof(float64), &float64);
	if(!float64_item)
		err("failed to create float64 item");

	if(!cseproto_add_item(msg, float64_item))
		err("failed to add float64 item to message");
	
	string_item  = cseproto_create_item(6, CSE_WIRETYPE_LENDELIM, strlen(string), string);
	if(!string_item)
		err("failed to create string item");

	if(!cseproto_add_item(msg, string_item))
		err("failed to add string item to message");

	//mylog("LOG", "message size: %i", cseproto_message_size(msg));
	//mylog("LOG", "buckets: %i", msg->bucket_count);

	encoded_data_len = cseproto_encode(msg, &encoded_data);
	if(!encoded_data_len)
		err("failed to encode message");

	fh = fopen("test1.out", "w");
	if(!fh)
		err("failed to open test1.out: %s", strerror(errno));

	fwrite(encoded_data, encoded_data_len, 1, fh);
	fclose(fh);
	
	decoded = cseproto_create(7);
	if(!decoded)
		err("failed to create message struct");

	decoded_data_len = cseproto_decode_data(decoded, encoded_data_len, encoded_data);
	if(decoded_data_len != encoded_data_len)
		err("decode failed, encoded len:%i decoded len:%i", encoded_data_len, decoded_data_len);

	//mylog("LOG", "message size: %i", cseproto_message_size(msg));
	
	for(i = 0; i < decoded->bucket_count; ++i) {
		cseproto_item_t *item = decoded->buckets[i].head;
		//mylog("LOG", "item[%i]: ptr:%p", i, item);
		switch(item->wiretype) {
			case CSE_WIRETYPE_VARINT: // uint[32,64]_t, bool, enum
				mylog("LOG", "item[%i]: va:%llx", i, item->v.uint64);
				break;
				
			case CSE_WIRETYPE_SVARINT: // int[32,64]_t
				mylog("LOG", "item[%i]: sva:%llx", i, item->v.int64);
				break;
				
			case CSE_WIRETYPE_64BIT: // double, [su]fixed64_t
				mylog("LOG", "item[%i]: 64:%f", i, item->v.float64);
				mylog("LOG", "item[%i]: 64:%llx", i, item->v.uint64);
				break;
				
			case CSE_WIRETYPE_32BIT: // float, [su]fixed32_t
				mylog("LOG", "item[%i]: 32:%f", i, item->v.float32);
				mylog("LOG", "item[%i]: 32:%x", i, item->v.uint32);
				break;
				
			case CSE_WIRETYPE_LENDELIM: { // strings, binary data, embeded messages
				uint8_t buf[item->data_len+1];
				memset(buf, 0, item->data_len+1);
				memcpy(buf, item->v.data, item->data_len);
				mylog("LOG", "item[%i]: ld:%s", i, buf);
			}	break;

			default:
				mylog("ERR", "item[%i]: unknown type :(", i);
		}
	}

	
	return 1;
}

int test2(char *arg)
{
	FILE *fh = NULL;
	uint8_t *encoded_data = 0;
	uint32_t encoded_data_len = 0, decoded_data_len = 0;
	cseproto_t *decoded = NULL;
	uint32_t i = 0;
	
	fh = fopen("test1.out", "r");
	if(!fh)
		err("failed to open test1.out: %s", strerror(errno));

	fseek(fh, 0, SEEK_END);
	encoded_data_len = ftell(fh);
	fseek(fh, 0, SEEK_SET);

	encoded_data = calloc(1, encoded_data_len);
	if(!encoded_data)
		err("failed to allocate encoded data");
	
	fread(encoded_data, encoded_data_len, 1, fh);
	fclose(fh);
	
	decoded = cseproto_create(7);
	if(!decoded)
		err("failed to create message struct");
	
	decoded_data_len = cseproto_decode_data(decoded, encoded_data_len, encoded_data);
	if(decoded_data_len != encoded_data_len)
		err("decode failed, encoded len:%i decoded len:%i", encoded_data_len, decoded_data_len);

	for(i = 0; i < decoded->bucket_count; ++i) {
		cseproto_item_t *item = decoded->buckets[i].head;
		//mylog("LOG", "item[%i]: ptr:%p", i, item);
		switch(item->wiretype) {
			case CSE_WIRETYPE_VARINT: // uint[32,64]_t, bool, enum
				mylog("LOG", "item[%i]: va:%llx", i, item->v.uint64);
				break;
				
			case CSE_WIRETYPE_SVARINT: // int[32,64]_t
				mylog("LOG", "item[%i]: sva:%llx", i, item->v.int64);
				break;
				
			case CSE_WIRETYPE_64BIT: // double, [su]fixed64_t
				mylog("LOG", "item[%i]: 64:%f", i, item->v.float64);
				mylog("LOG", "item[%i]: 64:%llx", i, item->v.uint64);
				break;
				
			case CSE_WIRETYPE_32BIT: // float, [su]fixed32_t
				mylog("LOG", "item[%i]: 32:%f", i, item->v.float32);
				mylog("LOG", "item[%i]: 32:%x", i, item->v.uint32);
				break;
				
			case CSE_WIRETYPE_LENDELIM: { // strings, binary data, embeded messages
				uint8_t buf[item->data_len+1];
				memset(buf, 0, item->data_len+1);
				memcpy(buf, item->v.data, item->data_len);
				mylog("LOG", "item[%i]: ld:%s", i, buf);
			}	break;
			
			default:
				mylog("ERR", "item[%i]: unknown type :(", i);
		}
	}
	
	return 1;
}

struct {
	char *name;
	int (*proc)(char *arg);
} tests[] = {
	{ "test1", test1 },
	{ "test2", test2 },
	{ NULL, NULL },
};

int run(char *name, char *arg)
{
	int32_t i = 0;
	for(i = 0; tests[i].name; ++i) {
		if(strcmp(name, tests[i].name)==0) {
			current_test = name;
			return tests[i].proc(arg);
		}
	}

	return -1;
}

int main(int argc, char **argv)
{
	int32_t ret = -1;

	if(argc < 2) {
		printf("useage %s <testname> <arg>\n", argv[0]);
		return -1;
	}
	
	ret = run(argv[1], argc > 2 ? argv[2] : NULL);
	if(ret == -1) {
		printf("test %s doesn't exist\n", argv[1]);
		return -1;
	}
	else if(ret == 0) {
		printf("test %s failed\n", argv[1]);
		return -1;
	}
	else {
		printf("test %s succedded\n", argv[1]);
		return 0;
	}
	
	return -1;
}