/* Copyright 2016 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

int copy_scl_std_functions = 0;

#define SCL_STD_FUNCTIONS copy_scl_std_functions
#include "scl/memory.h"

#if !defined(COPY_BUF_SIZE)
#	define COPY_BUF_SIZE 67
#endif

#if defined(NEED_PRINT)
#	include <stdio.h>

	static void pa(char unsigned a[COPY_BUF_SIZE]) {
		int i;
		for (i = 0; i < COPY_BUF_SIZE; ++i) {
			printf("%02X ", a[i]);
		}
		printf("\n");
	}

	static void pi(unsigned i, unsigned j, unsigned k) {
		printf("i = %u j = %u k = %u: ", i, j, k);
	}
#else
	static void pa(char unsigned a[COPY_BUF_SIZE]) {
		;
	}

	static void pi(unsigned i, unsigned j, unsigned k) {
		;
	}
#endif

static void copy_check(void) {
	int volatile buf1[32] = {0};
	char unsigned sample[COPY_BUF_SIZE];
	int volatile buf2[32] = {0};
	char unsigned test[COPY_BUF_SIZE];
	int volatile buf3[32] = {0};
	char unsigned start[COPY_BUF_SIZE];
	int volatile buf4[32] = {0};
	unsigned volatile i, j, k;
	int ret;
	(void)buf1;
	(void)buf2;
	(void)buf3;
	(void)buf4;

	for (i = 0; i < (int)(sizeof(start) / sizeof(start[0])); ++i) {
		start[i] = (char unsigned)(i % 256);
	}
	memcpy(test, start, sizeof(start));
	memcpy(sample, start, sizeof(start));
	for (i = 0; i < sizeof(start) / sizeof(start[0]); ++i) {
		for (j = 0; j < sizeof(start) / sizeof(start[0]); ++j) {
			for (k = 0; k < sizeof(start) / sizeof(start[0]) - j; ++k) {

				ret = scl_copy(test + i, sizeof(test) - i * sizeof(test[0]),
							   test + j, k * sizeof(test[0]));
				SCL_ASSERT(ret == (sizeof(test) - i * sizeof(test[0]) >= k * sizeof(test[0])));
				if (ret) {
					memmove(sample + i, sample + j, k * sizeof(sample[0]));
					SCL_ASSERT(memcmp(test, sample, sizeof(test)) == 0);
					pi(i, j, k);
					pa(test);

					memcpy(test, start, sizeof(start));
					memcpy(sample, start, sizeof(start));
				}
			}
		}
	}
}

static void copy_reject(void) {
	int ret;
	int dest[1], src[2];

	ret = scl_copy(dest, sizeof(dest), src, sizeof(src));
	SCL_ASSERT(!ret);

	ret = scl_copy(dest, 0, src, sizeof(src));
	SCL_ASSERT(!ret);

	ret = scl_copy(dest, -1, src, sizeof(src));
	SCL_ASSERT(!ret);

	ret = scl_copy(dest, INT_MIN, src, sizeof(src));
	SCL_ASSERT(!ret);

	ret = scl_copy(dest, sizeof(dest), src, -1);
	SCL_ASSERT(!ret);

	ret = scl_copy(dest, sizeof(dest), src, INT_MIN);
	SCL_ASSERT(!ret);

	ret = scl_copy(dest, -1, src, -1);
	SCL_ASSERT(!ret);

	ret = scl_copy(dest, INT_MIN, src, INT_MIN);
	SCL_ASSERT(!ret);
}

static void do_tests(void) {
	copy_check();
	copy_reject();
}

#if defined(START_FUNC) && (START_FUNC == 1)
#	undef START_FUNC
#	define START_FUNC test_copy
#endif

#if defined(START_FUNC)
	extern void START_FUNC(void) {
		do_tests();
		copy_scl_std_functions = 1 - copy_scl_std_functions;
		do_tests();
	}
#else
	extern int main(int argc, char const **argv) {
		do_tests();
		copy_scl_std_functions = 1 - copy_scl_std_functions;
		do_tests();
		return 0;
	}
#endif
