summaryrefslogtreecommitdiffstats
path: root/tests/check_fixedpoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/check_fixedpoint.c')
-rw-r--r--tests/check_fixedpoint.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/tests/check_fixedpoint.c b/tests/check_fixedpoint.c
new file mode 100644
index 0000000..a37d370
--- /dev/null
+++ b/tests/check_fixedpoint.c
@@ -0,0 +1,353 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <check.h>
+#include <stdlib.h>
+
+#include "../src/lib/fixedpoint.h"
+
+#ifdef ENABLE_LLDPMED
+
+START_TEST(test_string_parsing_suffix)
+{
+ char *end;
+ fp_strtofp("4541T", &end, 14, 8);
+ ck_assert_int_eq(*end, 'T');
+ fp_strtofp("4541.U", &end, 14, 8);
+ ck_assert_int_eq(*end, 'U');
+ fp_strtofp("4541.676V", &end, 14, 8);
+ ck_assert_int_eq(*end, 'V');
+}
+END_TEST
+
+START_TEST(test_string_parsing_positive_int)
+{
+ struct fp_number fp = fp_strtofp("4541T", NULL, 14, 8);
+ ck_assert_int_eq(fp.integer.bits, 14);
+ ck_assert_int_eq(fp.integer.value, 4541);
+ ck_assert_int_eq(fp.fraction.bits, 8);
+ ck_assert_int_eq(fp.fraction.value, 0);
+ ck_assert_int_eq(fp.fraction.precision, 0);
+}
+END_TEST
+
+START_TEST(test_string_parsing_negative_int)
+{
+ struct fp_number fp = fp_strtofp("-4214N", NULL, 14, 8);
+ ck_assert_int_eq(fp.integer.bits, 14);
+ ck_assert_int_eq(fp.integer.value, -4214);
+ ck_assert_int_eq(fp.fraction.bits, 8);
+ ck_assert_int_eq(fp.fraction.value, 0);
+ ck_assert_int_eq(fp.fraction.precision, 0);
+}
+END_TEST
+
+START_TEST(test_string_parsing_positive_int_overflow)
+{
+ struct fp_number fp1 = fp_strtofp("4098", NULL, 13, 8);
+ struct fp_number fp2 = fp_strtofp("4096", NULL, 13, 8);
+ struct fp_number fp3 = fp_strtofp("4095", NULL, 13, 8);
+ struct fp_number fp4 = fp_strtofp("4094", NULL, 13, 8);
+ ck_assert_int_eq(fp1.integer.value, 4095);
+ ck_assert_int_eq(fp2.integer.value, 4095);
+ ck_assert_int_eq(fp3.integer.value, 4095);
+ ck_assert_int_eq(fp4.integer.value, 4094);
+}
+END_TEST
+
+START_TEST(test_string_parsing_negative_int_overflow)
+{
+ struct fp_number fp1 = fp_strtofp("-4097", NULL, 13, 8);
+ struct fp_number fp2 = fp_strtofp("-4096", NULL, 13, 8);
+ struct fp_number fp3 = fp_strtofp("-4095", NULL, 13, 8);
+ struct fp_number fp4 = fp_strtofp("-4094", NULL, 13, 8);
+ ck_assert_int_eq(fp1.integer.value, -4096);
+ ck_assert_int_eq(fp2.integer.value, -4096);
+ ck_assert_int_eq(fp3.integer.value, -4095);
+ ck_assert_int_eq(fp4.integer.value, -4094);
+}
+END_TEST
+
+START_TEST(test_string_parsing_positive_float)
+{
+ struct fp_number fp1 = fp_strtofp("1542.6250E", NULL, 13, 20);
+ ck_assert_int_eq(fp1.integer.value, 1542);
+ ck_assert_int_eq(fp1.fraction.precision, 14);
+ ck_assert_int_eq((fp1.fraction.value * 10000) >> fp1.fraction.bits, 6250);
+
+ struct fp_number fp2 = fp_strtofp("1542.06250E", NULL, 13, 4);
+ ck_assert_int_eq(fp2.integer.value, 1542);
+ ck_assert_int_eq(fp2.fraction.precision, 4);
+ ck_assert_int_eq((fp2.fraction.value * 10000) >> fp2.fraction.bits, 625);
+}
+END_TEST
+
+START_TEST(test_string_parsing_negative_float)
+{
+ struct fp_number fp = fp_strtofp("-11542.6250N", NULL, 15, 4);
+ ck_assert_int_eq(fp.integer.value, -11542);
+ ck_assert_int_eq(fp.fraction.precision, 4);
+ ck_assert_int_eq((fp.fraction.value * 10000) >> fp.fraction.bits, 6250);
+}
+END_TEST
+
+START_TEST(test_string_parsing_no_fract_part)
+{
+ struct fp_number fp = fp_strtofp("11542.", NULL, 15, 4);
+ ck_assert_int_eq(fp.integer.value, 11542);
+ ck_assert_int_eq(fp.fraction.value, 0);
+ ck_assert_int_eq(fp.fraction.precision, 1);
+}
+END_TEST
+
+START_TEST(test_string_parsing_no_int_part)
+{
+ struct fp_number fp = fp_strtofp(".6250E", NULL, 13, 4);
+ ck_assert_int_eq(fp.integer.value, 0);
+ ck_assert_int_eq(fp.fraction.precision, 4);
+ ck_assert_int_eq((fp.fraction.value * 10000) >> fp.fraction.bits, 6250);
+}
+END_TEST
+
+START_TEST(test_string_representation_positive_int)
+{
+ struct fp_number fp1 = fp_strtofp("214", NULL, 9, 9);
+ struct fp_number fp2 = fp_strtofp("11178.0000", NULL, 15, 9);
+ ck_assert_str_eq(fp_fptostr(fp1, NULL), "214");
+ ck_assert_str_eq(fp_fptostr(fp2, NULL), "11178");
+ ck_assert_str_eq(fp_fptostr(fp2, "ES"), "11178E");
+}
+END_TEST
+
+START_TEST(test_string_representation_negative_int)
+{
+ struct fp_number fp1 = fp_strtofp("-214", NULL, 9, 9);
+ struct fp_number fp2 = fp_strtofp("-11178.0000", NULL, 15, 9);
+ ck_assert_str_eq(fp_fptostr(fp1, NULL), "-214");
+ ck_assert_str_eq(fp_fptostr(fp2, NULL), "-11178");
+ ck_assert_str_eq(fp_fptostr(fp2, "ES"), "11178S");
+}
+END_TEST
+
+START_TEST(test_string_representation_positive_float)
+{
+ struct fp_number fp = fp_strtofp("214.6250", NULL, 9, 20);
+ ck_assert_str_eq(fp_fptostr(fp, NULL), "214.6250");
+ ck_assert_str_eq(fp_fptostr(fp, "ES"), "214.6250E");
+}
+END_TEST
+
+START_TEST(test_string_representation_positive_float_with_leading_zero)
+{
+ struct fp_number fp = fp_strtofp("214.06250", NULL, 9, 24);
+ ck_assert_str_eq(fp_fptostr(fp, NULL), "214.06250");
+ ck_assert_str_eq(fp_fptostr(fp, "ES"), "214.06250E");
+}
+END_TEST
+
+START_TEST(test_string_representation_negative_float)
+{
+ struct fp_number fp1 = fp_strtofp("-214.625", NULL, 22, 10);
+ struct fp_number fp2 = fp_strtofp("-415.5", NULL, 22, 4);
+ ck_assert_str_eq(fp_fptostr(fp1, NULL), "-214.625");
+ ck_assert_str_eq(fp_fptostr(fp2, NULL), "-415.5");
+ ck_assert_str_eq(fp_fptostr(fp2, "ES"), "415.5S");
+}
+END_TEST
+
+START_TEST(test_buffer_representation_positive_float)
+{
+ unsigned char buffer[5] = {};
+ unsigned char expected[] = { 0x21 << 2, 47 << 1, 0x68, 0x00, 0x00 };
+ /* 47.2031250 = 47 + 2**-3 + 2**-4 + 2**-6, precision = 9+24 */
+ struct fp_number fp = fp_strtofp("47.2031250", NULL, 9, 25);
+ fp_fptobuf(fp, buffer, 0);
+ fail_unless(memcmp(buffer, expected, sizeof(expected)) == 0);
+}
+END_TEST
+
+START_TEST(test_buffer_representation_negative_float)
+{
+ unsigned char buffer[5] = {};
+ unsigned char expected[] = { (0x21 << 2) | 3, 0xa1, 0x98, 0x00, 0x00 };
+ /* 47.2031250 = 000101111.0011010000000000000000000 */
+ /* -47.2031250 = 111010000.1100101111111111111111111 + 1 */
+ /* -47.2031250 = 111010000.1100110000000000000000000 */
+ struct fp_number fp = fp_strtofp("-47.2031250", NULL, 9, 25);
+ fp_fptobuf(fp, buffer, 0);
+ fail_unless(memcmp(buffer, expected, sizeof(expected)) == 0);
+}
+END_TEST
+
+START_TEST(test_buffer_representation_with_shift)
+{
+ unsigned char buffer[] = { 0x77, 0xc6, 0x0, 0x0, 0x0, 0x0, 0xc7 };
+ unsigned char expected[] = { 0x77, 0xc8, 0x45, 0xe6, 0x80, 0x00, 0x07 };
+ struct fp_number fp = fp_strtofp("47.2031250", NULL, 9, 25);
+ fp_fptobuf(fp, buffer, 12);
+ fail_unless(memcmp(buffer, expected, sizeof(buffer)) == 0);
+}
+END_TEST
+
+START_TEST(test_buffer_representation_altitude)
+{
+ unsigned char buffer[5] = {};
+ unsigned char expected[] = { (22 + 4) << 2, 0, 0, 14 << 4 | 1 << 3, 0 };
+ struct fp_number fp = fp_strtofp("14.5", NULL, 22, 8);
+ fp_fptobuf(fp, buffer, 0);
+ fail_unless(memcmp(buffer, expected, sizeof(buffer)) == 0);
+}
+END_TEST
+
+START_TEST(test_buffer_parsing_positive_float)
+{
+ unsigned char buffer[] = { 0x21 << 2, 47 << 1, 0x68, 0x00, 0x00 };
+ struct fp_number fp = fp_buftofp(buffer, 9, 25, 0);
+ ck_assert_int_eq(fp.integer.value, 47);
+ ck_assert_int_eq(fp.integer.bits, 9);
+ ck_assert_int_eq((fp.fraction.value * 10000000) >> fp.fraction.bits, 2031250);
+ ck_assert_int_eq(fp.fraction.bits, 25);
+ ck_assert_int_eq(fp.fraction.precision, 24);
+}
+END_TEST
+
+START_TEST(test_buffer_parsing_negative_float)
+{
+ unsigned char buffer[] = { (0x21 << 2) | 3, 0xa1, 0x98, 0x00, 0x00 };
+ struct fp_number fp = fp_buftofp(buffer, 9, 25, 0);
+ ck_assert_int_eq(fp.integer.value, -47);
+ ck_assert_int_eq(fp.integer.bits, 9);
+ ck_assert_int_eq((fp.fraction.value * 10000000) >> fp.fraction.bits, 2031250);
+ ck_assert_int_eq(fp.fraction.bits, 25);
+ ck_assert_int_eq(fp.fraction.precision, 24);
+}
+END_TEST
+
+/* This is some corner case */
+START_TEST(test_buffer_parsing_positive_float_2)
+{
+ unsigned char buffer[] = { 0x40, 0x9c, 0x80, 0x00, 0x00 };
+ struct fp_number fp = fp_buftofp(buffer, 9, 25, 0);
+ ck_assert_int_eq(fp.integer.value, 78);
+}
+END_TEST
+
+START_TEST(test_buffer_parsing_positive_float_with_shift)
+{
+ unsigned char buffer[] = { 0x77, 0xc8, 0x45, 0xe6, 0x80, 0x00, 0x07 };
+ struct fp_number fp = fp_buftofp(buffer, 9, 25, 12);
+ ck_assert_int_eq(fp.integer.value, 47);
+ ck_assert_int_eq(fp.integer.bits, 9);
+ ck_assert_int_eq((fp.fraction.value * 10000000) >> fp.fraction.bits, 2031250);
+ ck_assert_int_eq(fp.fraction.bits, 25);
+ ck_assert_int_eq(fp.fraction.precision, 24);
+}
+END_TEST
+
+START_TEST(test_buffer_parsing_negative_float_with_shift)
+{
+ unsigned char buffer[] = { 0x00, 0xff, (0x21 << 2) | 3, 0xa1, 0x98, 0x00,
+ 0x00 };
+ struct fp_number fp = fp_buftofp(buffer, 9, 25, 16);
+ ck_assert_int_eq(fp.integer.value, -47);
+ ck_assert_int_eq(fp.integer.bits, 9);
+ ck_assert_int_eq((fp.fraction.value * 10000000) >> fp.fraction.bits, 2031250);
+ ck_assert_int_eq(fp.fraction.bits, 25);
+ ck_assert_int_eq(fp.fraction.precision, 24);
+}
+END_TEST
+
+START_TEST(test_negate_positive)
+{
+ struct fp_number fp = fp_strtofp("14.5", NULL, 9, 25);
+ struct fp_number nfp = fp_negate(fp);
+ ck_assert_int_eq(nfp.integer.value, -14);
+ ck_assert_int_eq(fp.fraction.value, nfp.fraction.value);
+ ck_assert_str_eq(fp_fptostr(nfp, NULL), "-14.5");
+}
+END_TEST
+
+START_TEST(test_negate_negative)
+{
+ struct fp_number fp = fp_strtofp("-14.5", NULL, 9, 25);
+ struct fp_number nfp = fp_negate(fp);
+ ck_assert_int_eq(nfp.integer.value, 14);
+ ck_assert_int_eq(fp.fraction.value, nfp.fraction.value);
+ ck_assert_str_eq(fp_fptostr(nfp, NULL), "14.5");
+}
+END_TEST
+
+#endif
+
+static Suite *
+fixedpoint_suite(void)
+{
+ Suite *s = suite_create("Fixed point representation");
+
+#ifdef ENABLE_LLDPMED
+ TCase *tc_fp = tcase_create("Fixed point representation");
+ tcase_add_test(tc_fp, test_string_parsing_suffix);
+ tcase_add_test(tc_fp, test_string_parsing_positive_int);
+ tcase_add_test(tc_fp, test_string_parsing_negative_int);
+ tcase_add_test(tc_fp, test_string_parsing_no_fract_part);
+ tcase_add_test(tc_fp, test_string_parsing_no_int_part);
+ tcase_add_test(tc_fp, test_string_parsing_positive_int_overflow);
+ tcase_add_test(tc_fp, test_string_parsing_negative_int_overflow);
+ tcase_add_test(tc_fp, test_string_parsing_positive_float);
+ tcase_add_test(tc_fp, test_string_parsing_negative_float);
+ tcase_add_test(tc_fp, test_string_representation_positive_int);
+ tcase_add_test(tc_fp, test_string_representation_negative_int);
+ tcase_add_test(tc_fp, test_string_representation_positive_float);
+ tcase_add_test(tc_fp,
+ test_string_representation_positive_float_with_leading_zero);
+ tcase_add_test(tc_fp, test_string_representation_negative_float);
+ tcase_add_test(tc_fp, test_buffer_representation_positive_float);
+ tcase_add_test(tc_fp, test_buffer_representation_negative_float);
+ tcase_add_test(tc_fp, test_buffer_representation_with_shift);
+ tcase_add_test(tc_fp, test_buffer_representation_altitude);
+ tcase_add_test(tc_fp, test_buffer_parsing_positive_float);
+ tcase_add_test(tc_fp, test_buffer_parsing_positive_float_2);
+ tcase_add_test(tc_fp, test_buffer_parsing_negative_float);
+ tcase_add_test(tc_fp, test_buffer_parsing_positive_float_with_shift);
+ tcase_add_test(tc_fp, test_buffer_parsing_negative_float_with_shift);
+ tcase_add_test(tc_fp, test_negate_positive);
+ tcase_add_test(tc_fp, test_negate_negative);
+ suite_add_tcase(s, tc_fp);
+#endif
+
+ return s;
+}
+
+/* Disable leak detection sanitizer */
+int __lsan_is_turned_off(void);
+int
+__lsan_is_turned_off(void)
+{
+ return 1;
+}
+
+int
+main()
+{
+ int number_failed;
+ Suite *s = fixedpoint_suite();
+ SRunner *sr = srunner_create(s);
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}