// SPDX-License-Identifier: 0BSD

#include "uuid.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>


static const char expecting[]                          = "encode: STR:     f50c5fcc-6b66-11ef-bafc-efdff7d5f2f6\n"
                                                         "        SIV:     325725109554302597798550804656796594934\n"
                                                         "decode: variant: DCE 1.1, ISO/IEC 11578:1996\n"
                                                         "        version: 1 (time and node based)\n"
                                                         "        content: time:  2024-09-05 09:12:21.383982.0 UTC\n"
                                                         "                 clock: 15100 (usually random)\n"
                                                         "                 node:  ef:df:f7:d5:f2:f6 (local multicast)\n";
static const char expecting_str[]                      = "f50c5fcc-6b66-11ef-bafc-efdff7d5f2f6";
static const char expecting_siv[]                      = "325725109554302597798550804656796594934";
static const unsigned char expecting_bin[UUID_LEN_BIN] = {0xF5, 0x0C, 0x5F, 0xCC, 0x6B, 0x66, 0x11, 0xEF, 0xBA, 0xFC, 0xEF, 0xDF, 0xF7, 0xD5, 0xF2, 0xF6};
#define assert_eq_expecting_str(uuid, tp, val)                                   \
	{                                                                              \
		char * desc = NULL;                                                          \
		size_t desc_len;                                                             \
		assert(uuid_export(uuid, tp, &desc, &desc_len) == UUID_RC_OK);               \
		assert(!strcmp(desc, val));                                                  \
		assert(desc_len == (tp == UUID_FMT_SIV ? (UUID_LEN_SIV + 1) : sizeof(val))); \
		free(desc);                                                                  \
	}
#define assert_eq_expecting_bin(uuid, val)                                   \
	{                                                                          \
		unsigned char * desc = NULL;                                             \
		size_t desc_len;                                                         \
		assert(uuid_export(uuid, UUID_FMT_BIN, &desc, &desc_len) == UUID_RC_OK); \
		assert(desc_len == sizeof(val));                                         \
		assert(!memcmp(desc, val, sizeof(val)));                                 \
		free(desc);                                                              \
	}
#define assert_eq_expecting(uuid)                             \
	assert_eq_expecting_str(uuid, UUID_FMT_TXT, expecting);     \
	assert_eq_expecting_str(uuid, UUID_FMT_STR, expecting_str); \
	assert_eq_expecting_str(uuid, UUID_FMT_SIV, expecting_siv); \
	assert_eq_expecting_bin(uuid, expecting_bin);

int main() {
	uuid_t * uuid;
	assert(uuid_create(&uuid) == UUID_RC_OK);

	assert_eq_expecting_str(uuid, UUID_FMT_TXT,
	                        "encode: STR:     00000000-0000-0000-0000-000000000000\n"
	                        "        SIV:     0\n"
	                        "decode: variant: n.a.\n"
	                        "        version: 0 (n.a.)\n"
	                        "        content: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00\n"
	                        "                 (special case: DCE 1.1 Nil UUID)\n");
	assert_eq_expecting_str(uuid, UUID_FMT_STR, "00000000-0000-0000-0000-000000000000");
	assert_eq_expecting_str(uuid, UUID_FMT_SIV, "0");
	static const unsigned char null_bin[UUID_LEN_BIN] = {};
	assert_eq_expecting_bin(uuid, null_bin);


	assert(uuid_import(uuid, UUID_FMT_STR, expecting_str, sizeof(expecting_str)) == UUID_RC_OK);
	assert_eq_expecting(uuid);

	assert(uuid_import(uuid, UUID_FMT_SIV, expecting_siv, sizeof(expecting_siv)) == UUID_RC_OK);
	assert_eq_expecting(uuid);
	assert(uuid_import(uuid, UUID_FMT_SIV, expecting_siv, strlen(expecting_siv)) == UUID_RC_OK);
	assert_eq_expecting(uuid);
	char shortbuf_nonul[sizeof(expecting_siv)];
	strcpy(shortbuf_nonul, expecting_siv);
	shortbuf_nonul[sizeof(shortbuf_nonul) - 1] = 'Q';
	assert(uuid_import(uuid, UUID_FMT_SIV, shortbuf_nonul, strlen(expecting_siv)) == UUID_RC_OK);
	assert_eq_expecting(uuid);
	shortbuf_nonul[sizeof(shortbuf_nonul) - 1] = '1';
	assert(uuid_import(uuid, UUID_FMT_SIV, shortbuf_nonul, strlen(expecting_siv)) == UUID_RC_OK);
	assert_eq_expecting(uuid);

	assert(uuid_import(uuid, UUID_FMT_BIN, expecting_bin, sizeof(expecting_bin)) == UUID_RC_OK);
	assert_eq_expecting(uuid);


	assert(uuid_import(uuid, UUID_FMT_STR, "4eb841ca-ce98-4590-8ea2-c4643bfa", sizeof("4eb841ca-ce98-4590-8ea2-c4643bfa")) == UUID_RC_ARG);
	assert(uuid_import(uuid, UUID_FMT_STR, "4eb841ca-ce98-4590-8ea2-c4643bfaqwe", sizeof("4eb841ca-ce98-4590-8ea2-c4643bfaqwe")) == UUID_RC_ARG);
	assert(uuid_import(uuid, UUID_FMT_STR, "4eb841ca-ce98-4590-8ea2-c4643bfa537bad", sizeof("4eb841ca-ce98-4590-8ea2-c4643bfa537bad")) == UUID_RC_ARG);

	assert(uuid_destroy(uuid) == UUID_RC_OK);
}
