#include "../test.h"

#include <aerospike/as_queue.h>
#include <citrusleaf/alloc.h>

/******************************************************************************
 * TEST CASES
 *****************************************************************************/

TEST( types_queue_stack, "as_queue stack mode" ) {
	// Initialize queue on stack.
    as_queue v;
	as_queue_inita(&v, sizeof(int), 10);
	
	for (int i = 0; i < 9; i++) {
		as_queue_push(&v, &i);
	}
	
	assert(as_queue_size(&v) == 9);
	assert(v.capacity == 10);
	assert(v.flags == 0);
	
	// Add more items so queue is resized/converted to heap.
	int i = 9;
	as_queue_push(&v, &i);
	i = 10;
	as_queue_push(&v, &i);
	
	assert(as_queue_size(&v) == 11);
	assert(v.capacity == 20);
	assert(v.flags == 1);
	
	int result;
	for (int i = 0; i < 11; i++) {
		if (as_queue_pop(&v, &result)) {
			assert(result == i);
		}
		else {
			assert(false);
		}
	}
	
	assert(as_queue_size(&v) == 0);
	assert(v.capacity == 20);
	assert(v.flags == 1);
	
	// Destroy queue.
    as_queue_destroy(&v);
}

TEST( types_queue_heap_init, "as_queue heap with init" ) {
	// Initialize array on heap.
    as_queue v;
	as_queue_init(&v, sizeof(int), 10);
	
	for (int i = 0; i < 9; i++) {
		as_queue_push(&v, &i);
	}
	
	assert(as_queue_size(&v) == 9);
	assert(v.capacity == 10);
	assert(v.flags == 1);
		
	// Add more items so queue is resized.
	int i = 9;
	as_queue_push(&v, &i);
	i = 10;
	as_queue_push(&v, &i);
	
	assert(as_queue_size(&v) == 11);
	assert(v.capacity == 20);
	assert(v.flags == 1);
	
	int result;
	for (int i = 0; i < 11; i++) {
		if (as_queue_pop(&v, &result)) {
			assert(result == i);
		}
		else {
			assert(false);
		}
	}
	
	assert(as_queue_size(&v) == 0);
	assert(v.capacity == 20);
	assert(v.flags == 1);

	// Destroy queue.
    as_queue_destroy(&v);
}

TEST( types_queue_heap_create, "as_queue heap with create" ) {
	// Initialize array on heap.
    as_queue* v = as_queue_create(sizeof(int), 10);
	
	for (int i = 0; i < 9; i++) {
		as_queue_push(v, &i);
	}
	
	assert(as_queue_size(v) == 9);
	assert(v->capacity == 10);
	assert(v->flags == 3);
		
	// Add more items so queue is resized.
	int i = 9;
	as_queue_push(v, &i);
	i = 10;
	as_queue_push(v, &i);
	
	assert(as_queue_size(v) == 11);
	assert(v->capacity == 20);
	assert(v->flags == 3);
	
	int result;
	for (int i = 0; i < 11; i++) {
		if (as_queue_pop(v, &result)) {
			assert(result == i);
		}
		else {
			assert(false);
		}
	}
	
	assert(as_queue_size(v) == 0);
	assert(v->capacity == 20);
	assert(v->flags == 3);

	// Destroy queue.
    as_queue_destroy(v);
}

TEST( types_queue_pointers, "as_queue pointer elements" ) {
    as_queue v;
	as_queue_init(&v, sizeof(int*), 10);
	
	for (int i = 0; i < 11; i++) {
		int* val = cf_malloc(sizeof(int*));
		*val = i;
		as_queue_push(&v, &val);
	}
		
	assert(as_queue_size(&v) == 11);
	assert(v.capacity == 20);
	assert(v.flags == 1);
	
	int* result;
	for (int i = 0; i < 11; i++) {
		if (as_queue_pop(&v, &result)) {
			assert(*result == i);
		}
		else {
			assert(false);
		}
		cf_free(result);
	}

    as_queue_destroy(&v);
}

TEST( types_queue_push_head, "as_queue push head" ) {
	as_queue v;
	as_queue_init(&v, sizeof(int), 10);

	for (int i = 0; i < 11; i++) {
		as_queue_push_head(&v, &i);
	}

	assert(as_queue_size(&v) == 11);
	assert(v.capacity == 20);
	assert(v.flags == 1);

	int result;
	for (int i = 10; i >= 0; i--) {
		if (as_queue_pop(&v, &result)) {
			assert(result == i);
		}
		else {
			assert(false);
		}
	}

	as_queue_destroy(&v);
}

TEST( types_queue_pop_tail, "as_queue pop tail" ) {
	as_queue v;
	as_queue_init(&v, sizeof(int), 10);

	for (int i = 0; i < 11; i++) {
		as_queue_push(&v, &i);
	}

	assert(as_queue_size(&v) == 11);
	assert(v.capacity == 20);
	assert(v.flags == 1);

	int result;
	for (int i = 10; i >= 0; i--) {
		if (as_queue_pop_tail(&v, &result)) {
			assert(result == i);
		}
		else {
			assert(false);
		}
	}

	as_queue_destroy(&v);
}

TEST( types_queue_push_limit, "as_queue push limit" ) {
	as_queue v;
	as_queue_init(&v, sizeof(int), 10);

	for (int i = 0; i < 10; i++) {
		as_queue_push(&v, &i);
	}

	assert(as_queue_size(&v) == 10);
	assert(v.capacity == 10);
	assert(v.flags == 1);

	int val = 11;
	bool status = as_queue_push_limit(&v, &val);
	assert(status == false);

	status = as_queue_push_head_limit(&v, &val);
	assert(status == false);

	as_queue_destroy(&v);
}

/******************************************************************************
 * TEST SUITE
 *****************************************************************************/

SUITE( types_queue, "as_queue" ) {
    suite_add( types_queue_stack );
    suite_add( types_queue_heap_init );
    suite_add( types_queue_heap_create );
    suite_add( types_queue_pointers );
	suite_add( types_queue_push_head );
	suite_add( types_queue_pop_tail );
	suite_add( types_queue_push_limit );
}
