/* 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.
 */
#include "scl/compare.h"

#include <limits.h>

#if defined(SCL_USE_ASSERT_H) && (SCL_USE_ASSERT_H == 0)
#	include <stdlib.h>
#	if defined(EXIT_FAILURE)
#		define SCL_ASSERT(assertion) { \
			if (!(assertion)) \
				exit(EXIT_FAILURE); \
		}
#	else
#		define SCL_ASSERT(assertion) { \
			if (!(assertion)) \
				exit(1); \
		}
#	endif
#else
#	include <assert.h>
#	define SCL_ASSERT(assertion) assert(assertion)
#endif

static void do_tests(void) {
	int/*bool*/ ret;
	/* expression equal to false, because of signed -1 interpreted as unsigned
	 * UINT_MAX
	 * update: explicit cast need to prevent warnings */
	ret = (unsigned)-1 < 1u;
	SCL_ASSERT(!ret);

	/* TODO add for short and char and for same signedness numbers */

	ret = scl_cmp(-1, 1u) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(-1, 1u) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(1u, -1) > 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(1, 2u) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(1, 2u) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(2u, 1) > 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(INT_MAX, 2u) > 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(INT_MAX, 2u) > 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(2u, INT_MAX) < 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(INT_MAX, INT_MAX) == 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(INT_MAX, INT_MAX) == 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(INT_MIN, 0u) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(INT_MIN, 0u) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(0u, INT_MIN) > 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(INT_MIN, UINT_MAX) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(INT_MIN, UINT_MAX) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(UINT_MAX, INT_MIN) > 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(0, 0) == 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(0, 0) == 0;
	SCL_ASSERT(ret);


	ret = (unsigned long)-1l < 1ul;
	SCL_ASSERT(!ret);

	ret = scl_cmp(-1l, 1ul) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(-1l, 1ul) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(1ul, -1l) > 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(1l, 2ul) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(1l, 2ul) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(2ul, 1l) > 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(LONG_MAX, 2u) > 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(LONG_MAX, 2u) > 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(2u, LONG_MAX) < 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(LONG_MAX, LONG_MAX) == 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(LONG_MAX, LONG_MAX) == 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(LONG_MIN, 0ul) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(LONG_MIN, 0ul) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(0ul, LONG_MIN) > 0;
	SCL_ASSERT(ret);

	ret = scl_cmp(LONG_MIN, ULONG_MAX) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(LONG_MIN, ULONG_MAX) < 0;
	SCL_ASSERT(ret);
	ret = SCL_CMP(ULONG_MAX, LONG_MIN) > 0;
	SCL_ASSERT(ret);

#	if SCL_USE_LONG_LONG
		ret = (unsigned long long)-1ll < 1ull;
		SCL_ASSERT(!ret);

		ret = scl_cmp(-1ll, 1ull) < 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(-1ll, 1ull) < 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(1ull, -1ll) > 0;
		SCL_ASSERT(ret);

		ret = scl_cmp(1l, 2ul) < 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(1l, 2ul) < 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(2ul, 1l) > 0;
		SCL_ASSERT(ret);

		ret = scl_cmp(LLONG_MAX, 2u) > 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(LLONG_MAX, 2u) > 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(2u, LLONG_MAX) < 0;
		SCL_ASSERT(ret);

		ret = scl_cmp(LLONG_MAX, LLONG_MAX) == 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(LLONG_MAX, LLONG_MAX) == 0;
		SCL_ASSERT(ret);

		ret = scl_cmp(LLONG_MIN, 0ul) < 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(LLONG_MIN, 0ul) < 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(0ul, LLONG_MIN) > 0;
		SCL_ASSERT(ret);

		ret = scl_cmp(LLONG_MIN, ULLONG_MAX) < 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(LLONG_MIN, ULLONG_MAX) < 0;
		SCL_ASSERT(ret);
		ret = SCL_CMP(ULLONG_MAX, LLONG_MIN) > 0;
		SCL_ASSERT(ret);
#	endif
}

#if defined(START_FUNC) && (START_FUNC == 1)
#	undef START_FUNC
#	define START_FUNC test_compare
#endif

#if defined(START_FUNC)
	extern void START_FUNC(void) {
		do_tests();
	}
#else

#	include <stdio.h>

	extern int main(int argc, char const **argv) {
		do_tests();
		puts("compare finish");
		return 0;
	}
#endif
