#include "stream_expectations.h"

/* Ordered from 0 to queue_size - 1 */
struct test_assertion assertions_queue[MAX_QUEUE_ITEMS];
size_t queue_size = 0;
size_t current_expectation = 0;
decoder_t * decoder;


void set_decoder(decoder_t * dec)
{
	decoder = dec;
}

/* Callbacks */
struct test_assertion current()
{
	return assertions_queue[current_expectation];
}

/* Assertions builders and matcher callbacks */
<% %w(u neg).each do |type| %>
	<% [8, 16, 32, 64].each do |width| %>
		void assert_<%= type %>int<%= width %>_eq(uint<%= width %>_t actual)
		{
			assertions_queue[queue_size++] = (struct test_assertion) { <%= type.upcase %>INT<%= width %>_EQ, (union test_expectation_data) { .int<%= width %> = actual } };
		}

		void <%= type %>int<%= width %>_callback(void * context, uint<%= width %>_t actual)
		{
			assert_true(current().expectation == <%= type.upcase %>INT<%= width %>_EQ);
			assert_true(current().data.int<%= width %> == actual);
			current_expectation++;
		}
	<% end %>
<% end %>

void assert_bstring_mem_eq(cbor_data address, size_t length)
{
	assertions_queue[queue_size++] = (struct test_assertion) { BSTRING_MEM_EQ, (union test_expectation_data) { .string = { address, length } } };
}

void byte_string_callback(void * context, cbor_data address, size_t length)
{
	assert_true(current().expectation == BSTRING_MEM_EQ);
	assert_true(current().data.string.address == address);
	assert_true(current().data.string.length == length);
	current_expectation++;
}

void assert_bstring_indef_start()
{
	assertions_queue[queue_size++] = (struct test_assertion) { .expectation = BSTRING_INDEF_START };
}

void byte_string_start_callback(void * context)
{
	assert_true(current().expectation == BSTRING_INDEF_START);
	current_expectation++;
}

void assert_indef_break()
{
	assertions_queue[queue_size++] = (struct test_assertion) { .expectation = INDEF_BREAK };
}

void indef_break_callback(void * context)
{
	assert_true(current().expectation == INDEF_BREAK);
	current_expectation++;
}

<% %w(array map).each do |type| %>
	void assert_<%= type %>_start(size_t length)
	{
		assertions_queue[queue_size++] = (struct test_assertion) { <%= type.upcase %>_START, { .length = length } };
	}


	void <%= type %>_start_callback(void * context, size_t length)
	{
		assert_true(current().expectation == <%= type.upcase %>_START);
		assert_true(current().data.length == length);
		current_expectation++;
	}

	void assert_indef_<%= type %>_start()
	{
		assertions_queue[queue_size++] = (struct test_assertion) { .expectation = <%= type.upcase %>_INDEF_START };
	}

	void indef_<%= type %>_start_callback(void * context)
	{
		assert_true(current().expectation == <%= type.upcase %>_INDEF_START);
		current_expectation++;
	}
<% end %>

void assert_tag_eq(uint64_t value)
{
	assertions_queue[queue_size++] = (struct test_assertion) { TAG_EQ , { .int64 = value } };
}

void tag_callback(void * context, uint64_t value)
{
	assert_true(current().expectation == TAG_EQ);
	assert_true(current().data.int64 == value);
	current_expectation++;
}


<% [['half', 2, 'float'], ['float', 4], ['double', 8]].each do |decimal| %>
	void assert_<%= decimal[0] %>(<%= decimal[2] || decimal[0] %> value)
	{
		assertions_queue[queue_size++] = (struct test_assertion) { <%= decimal[0].upcase %>_EQ, { .float<%= decimal[1] %> = value } };
	}

	void <%= decimal[0] %>_callback(void * context, <%= decimal[2] || decimal[0] %> actual)
	{
		assert_true(current().expectation == <%= decimal[0].upcase %>_EQ);
		assert_true(current().data.float<%= decimal[1] %> == actual);
		current_expectation++;
	}
<% end %>

void assert_bool(bool value)
{
	assertions_queue[queue_size++] = (struct test_assertion) { BOOL_EQ, { .boolean = value } };
}

void assert_nil()
{
	assertions_queue[queue_size++] = (struct test_assertion) { .expectation = NIL };
}

void assert_undef()
{
	assertions_queue[queue_size++] = (struct test_assertion) { .expectation = UNDEF };
}


void bool_callback(void * context, bool actual)
{
	assert_true(current().expectation == BOOL_EQ);
	assert_true(current().data.boolean == actual);
	current_expectation++;
}

void null_callback(void * context)
{
	assert_true(current().expectation == NIL);
	current_expectation++;
}

void undef_callback(void * context)
{
	assert_true(current().expectation == UNDEF);
	current_expectation++;
}

const struct cbor_callbacks asserting_callbacks = {
	<% %w(u neg).each do |type| %>
		<% [8, 16, 32, 64].each do |width| %>
			.<%= type %>int<%= width %> = &<%= type %>int<%= width %>_callback,
		<% end %>
	<% end %>

	.byte_string = &byte_string_callback,
	.byte_string_start = &byte_string_start_callback,

	<% %w(array map).each do |type| %>
		.<%= type %>_start = &<%= type %>_start_callback,
		.indef_<%= type %>_start = &indef_<%= type %>_start_callback,
	<% end %>

	.tag = &tag_callback,

	<% [['half', 2], ['float', 4], ['double', 8]].each do |decimal| %>
		.float<%= decimal[1] %> = &<%= decimal[0] %>_callback,
	<% end %>

	.undefined = &undef_callback,
	.boolean = &bool_callback,
	.null = &null_callback,
	.indef_break = &indef_break_callback
};

struct cbor_decoder_result decode(cbor_data source, size_t source_size)
{
	struct cbor_decoder_result result = decoder(source, source_size, &asserting_callbacks, NULL);
	/* Check remaining assertions */

	assert_true(current_expectation == queue_size);
	/* Clean up */
	current_expectation = queue_size = 0;
	return result;
}


