1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include "../src/lib/fixedpoint.h"
25 START_TEST(test_string_parsing_suffix
) {
27 fp_strtofp("4541T", &end
, 14, 8);
28 ck_assert_int_eq(*end
, 'T');
29 fp_strtofp("4541.U", &end
, 14, 8);
30 ck_assert_int_eq(*end
, 'U');
31 fp_strtofp("4541.676V", &end
, 14, 8);
32 ck_assert_int_eq(*end
, 'V');
36 START_TEST(test_string_parsing_positive_int
) {
37 struct fp_number fp
= fp_strtofp("4541T", NULL
, 14, 8);
38 ck_assert_int_eq(fp
.integer
.bits
, 14);
39 ck_assert_int_eq(fp
.integer
.value
, 4541);
40 ck_assert_int_eq(fp
.fraction
.bits
, 8);
41 ck_assert_int_eq(fp
.fraction
.value
, 0);
42 ck_assert_int_eq(fp
.fraction
.precision
, 0);
46 START_TEST(test_string_parsing_negative_int
) {
47 struct fp_number fp
= fp_strtofp("-4214N", NULL
, 14, 8);
48 ck_assert_int_eq(fp
.integer
.bits
, 14);
49 ck_assert_int_eq(fp
.integer
.value
, -4214);
50 ck_assert_int_eq(fp
.fraction
.bits
, 8);
51 ck_assert_int_eq(fp
.fraction
.value
, 0);
52 ck_assert_int_eq(fp
.fraction
.precision
, 0);
56 START_TEST(test_string_parsing_positive_int_overflow
) {
57 struct fp_number fp1
= fp_strtofp("4098", NULL
, 13, 8);
58 struct fp_number fp2
= fp_strtofp("4096", NULL
, 13, 8);
59 struct fp_number fp3
= fp_strtofp("4095", NULL
, 13, 8);
60 struct fp_number fp4
= fp_strtofp("4094", NULL
, 13, 8);
61 ck_assert_int_eq(fp1
.integer
.value
, 4095);
62 ck_assert_int_eq(fp2
.integer
.value
, 4095);
63 ck_assert_int_eq(fp3
.integer
.value
, 4095);
64 ck_assert_int_eq(fp4
.integer
.value
, 4094);
68 START_TEST(test_string_parsing_negative_int_overflow
) {
69 struct fp_number fp1
= fp_strtofp("-4097", NULL
, 13, 8);
70 struct fp_number fp2
= fp_strtofp("-4096", NULL
, 13, 8);
71 struct fp_number fp3
= fp_strtofp("-4095", NULL
, 13, 8);
72 struct fp_number fp4
= fp_strtofp("-4094", NULL
, 13, 8);
73 ck_assert_int_eq(fp1
.integer
.value
, -4096);
74 ck_assert_int_eq(fp2
.integer
.value
, -4096);
75 ck_assert_int_eq(fp3
.integer
.value
, -4095);
76 ck_assert_int_eq(fp4
.integer
.value
, -4094);
80 START_TEST(test_string_parsing_positive_float
) {
81 struct fp_number fp1
= fp_strtofp("1542.6250E", NULL
, 13, 20);
82 ck_assert_int_eq(fp1
.integer
.value
, 1542);
83 ck_assert_int_eq(fp1
.fraction
.precision
, 14);
84 ck_assert_int_eq((fp1
.fraction
.value
* 10000) >> fp1
.fraction
.bits
, 6250);
86 struct fp_number fp2
= fp_strtofp("1542.06250E", NULL
, 13, 4);
87 ck_assert_int_eq(fp2
.integer
.value
, 1542);
88 ck_assert_int_eq(fp2
.fraction
.precision
, 4);
89 ck_assert_int_eq((fp2
.fraction
.value
* 10000) >> fp2
.fraction
.bits
, 625);
93 START_TEST(test_string_parsing_negative_float
) {
94 struct fp_number fp
= fp_strtofp("-11542.6250N", NULL
, 15, 4);
95 ck_assert_int_eq(fp
.integer
.value
, -11542);
96 ck_assert_int_eq(fp
.fraction
.precision
, 4);
97 ck_assert_int_eq((fp
.fraction
.value
* 10000) >> fp
.fraction
.bits
, 6250);
101 START_TEST(test_string_parsing_no_fract_part
) {
102 struct fp_number fp
= fp_strtofp("11542.", NULL
, 15, 4);
103 ck_assert_int_eq(fp
.integer
.value
, 11542);
104 ck_assert_int_eq(fp
.fraction
.value
, 0);
105 ck_assert_int_eq(fp
.fraction
.precision
, 1);
109 START_TEST(test_string_parsing_no_int_part
) {
110 struct fp_number fp
= fp_strtofp(".6250E", NULL
, 13, 4);
111 ck_assert_int_eq(fp
.integer
.value
, 0);
112 ck_assert_int_eq(fp
.fraction
.precision
, 4);
113 ck_assert_int_eq((fp
.fraction
.value
* 10000) >> fp
.fraction
.bits
, 6250);
118 START_TEST(test_string_representation_positive_int
) {
119 struct fp_number fp1
= fp_strtofp("214", NULL
, 9, 9);
120 struct fp_number fp2
= fp_strtofp("11178.0000", NULL
, 15, 9);
121 ck_assert_str_eq(fp_fptostr(fp1
, NULL
), "214");
122 ck_assert_str_eq(fp_fptostr(fp2
, NULL
), "11178");
123 ck_assert_str_eq(fp_fptostr(fp2
, "ES"), "11178E");
127 START_TEST(test_string_representation_negative_int
) {
128 struct fp_number fp1
= fp_strtofp("-214", NULL
, 9, 9);
129 struct fp_number fp2
= fp_strtofp("-11178.0000", NULL
, 15, 9);
130 ck_assert_str_eq(fp_fptostr(fp1
, NULL
), "-214");
131 ck_assert_str_eq(fp_fptostr(fp2
, NULL
), "-11178");
132 ck_assert_str_eq(fp_fptostr(fp2
, "ES"), "11178S");
136 START_TEST(test_string_representation_positive_float
) {
137 struct fp_number fp
= fp_strtofp("214.6250", NULL
, 9, 20);
138 ck_assert_str_eq(fp_fptostr(fp
, NULL
), "214.6250");
139 ck_assert_str_eq(fp_fptostr(fp
, "ES"), "214.6250E");
143 START_TEST(test_string_representation_positive_float_with_leading_zero
) {
144 struct fp_number fp
= fp_strtofp("214.06250", NULL
, 9, 24);
145 ck_assert_str_eq(fp_fptostr(fp
, NULL
), "214.06250");
146 ck_assert_str_eq(fp_fptostr(fp
, "ES"), "214.06250E");
150 START_TEST(test_string_representation_negative_float
) {
151 struct fp_number fp1
= fp_strtofp("-214.625", NULL
, 22, 10);
152 struct fp_number fp2
= fp_strtofp("-415.5", NULL
, 22, 4);
153 ck_assert_str_eq(fp_fptostr(fp1
, NULL
), "-214.625");
154 ck_assert_str_eq(fp_fptostr(fp2
, NULL
), "-415.5");
155 ck_assert_str_eq(fp_fptostr(fp2
, "ES"), "415.5S");
159 START_TEST(test_buffer_representation_positive_float
) {
160 unsigned char buffer
[5] = {};
161 unsigned char expected
[] = { 0x21 << 2, 47 << 1, 0x68, 0x00, 0x00 };
162 /* 47.2031250 = 47 + 2**-3 + 2**-4 + 2**-6, precision = 9+24 */
163 struct fp_number fp
= fp_strtofp("47.2031250", NULL
, 9, 25);
164 fp_fptobuf(fp
, buffer
, 0);
165 fail_unless(memcmp(buffer
, expected
, sizeof(expected
)) == 0);
169 START_TEST(test_buffer_representation_negative_float
) {
170 unsigned char buffer
[5] = {};
171 unsigned char expected
[] = { (0x21 << 2) | 3, 0xa1, 0x98, 0x00, 0x00 };
172 /* 47.2031250 = 000101111.0011010000000000000000000 */
173 /* -47.2031250 = 111010000.1100101111111111111111111 + 1 */
174 /* -47.2031250 = 111010000.1100110000000000000000000 */
175 struct fp_number fp
= fp_strtofp("-47.2031250", NULL
, 9, 25);
176 fp_fptobuf(fp
, buffer
, 0);
177 fail_unless(memcmp(buffer
, expected
, sizeof(expected
)) == 0);
181 START_TEST(test_buffer_representation_with_shift
) {
182 unsigned char buffer
[] = { 0x77, 0xc6, 0x0, 0x0, 0x0, 0x0, 0xc7 };
183 unsigned char expected
[] = { 0x77, 0xc8, 0x45, 0xe6, 0x80, 0x00, 0x07 };
184 struct fp_number fp
= fp_strtofp("47.2031250", NULL
, 9, 25);
185 fp_fptobuf(fp
, buffer
, 12);
186 fail_unless(memcmp(buffer
, expected
, sizeof(buffer
)) == 0);
190 START_TEST(test_buffer_representation_altitude
) {
191 unsigned char buffer
[5] = {};
192 unsigned char expected
[] = { (22 + 4) << 2, 0, 0, 14 << 4 | 1 << 3, 0 };
193 struct fp_number fp
= fp_strtofp("14.5", NULL
, 22, 8);
194 fp_fptobuf(fp
, buffer
, 0);
195 fail_unless(memcmp(buffer
, expected
, sizeof(buffer
)) == 0);
199 START_TEST(test_buffer_parsing_positive_float
) {
200 unsigned char buffer
[] = { 0x21 << 2, 47 << 1, 0x68, 0x00, 0x00 };
201 struct fp_number fp
= fp_buftofp(buffer
, 9, 25, 0);
202 ck_assert_int_eq(fp
.integer
.value
, 47);
203 ck_assert_int_eq(fp
.integer
.bits
, 9);
204 ck_assert_int_eq((fp
.fraction
.value
* 10000000) >> fp
.fraction
.bits
, 2031250);
205 ck_assert_int_eq(fp
.fraction
.bits
, 25);
206 ck_assert_int_eq(fp
.fraction
.precision
, 24);
210 START_TEST(test_buffer_parsing_negative_float
) {
211 unsigned char buffer
[] = { (0x21 << 2) | 3, 0xa1, 0x98, 0x00, 0x00 };
212 struct fp_number fp
= fp_buftofp(buffer
, 9, 25, 0);
213 ck_assert_int_eq(fp
.integer
.value
, -47);
214 ck_assert_int_eq(fp
.integer
.bits
, 9);
215 ck_assert_int_eq((fp
.fraction
.value
* 10000000) >> fp
.fraction
.bits
, 2031250);
216 ck_assert_int_eq(fp
.fraction
.bits
, 25);
217 ck_assert_int_eq(fp
.fraction
.precision
, 24);
221 /* This is some corner case */
222 START_TEST(test_buffer_parsing_positive_float_2
) {
223 unsigned char buffer
[] = { 0x40, 0x9c, 0x80, 0x00, 0x00 };
224 struct fp_number fp
= fp_buftofp(buffer
, 9, 25, 0);
225 ck_assert_int_eq(fp
.integer
.value
, 78);
229 START_TEST(test_buffer_parsing_positive_float_with_shift
) {
230 unsigned char buffer
[] = { 0x77, 0xc8, 0x45, 0xe6, 0x80, 0x00, 0x07 };
231 struct fp_number fp
= fp_buftofp(buffer
, 9, 25, 12);
232 ck_assert_int_eq(fp
.integer
.value
, 47);
233 ck_assert_int_eq(fp
.integer
.bits
, 9);
234 ck_assert_int_eq((fp
.fraction
.value
* 10000000) >> fp
.fraction
.bits
, 2031250);
235 ck_assert_int_eq(fp
.fraction
.bits
, 25);
236 ck_assert_int_eq(fp
.fraction
.precision
, 24);
240 START_TEST(test_buffer_parsing_negative_float_with_shift
) {
241 unsigned char buffer
[] = { 0x00, 0xff, (0x21 << 2) | 3, 0xa1, 0x98, 0x00, 0x00 };
242 struct fp_number fp
= fp_buftofp(buffer
, 9, 25, 16);
243 ck_assert_int_eq(fp
.integer
.value
, -47);
244 ck_assert_int_eq(fp
.integer
.bits
, 9);
245 ck_assert_int_eq((fp
.fraction
.value
* 10000000) >> fp
.fraction
.bits
, 2031250);
246 ck_assert_int_eq(fp
.fraction
.bits
, 25);
247 ck_assert_int_eq(fp
.fraction
.precision
, 24);
251 START_TEST(test_negate_positive
) {
252 struct fp_number fp
= fp_strtofp("14.5", NULL
, 9, 25);
253 struct fp_number nfp
= fp_negate(fp
);
254 ck_assert_int_eq(nfp
.integer
.value
, -14);
255 ck_assert_int_eq(fp
.fraction
.value
, nfp
.fraction
.value
);
256 ck_assert_str_eq(fp_fptostr(nfp
, NULL
), "-14.5");
260 START_TEST(test_negate_negative
) {
261 struct fp_number fp
= fp_strtofp("-14.5", NULL
, 9, 25);
262 struct fp_number nfp
= fp_negate(fp
);
263 ck_assert_int_eq(nfp
.integer
.value
, 14);
264 ck_assert_int_eq(fp
.fraction
.value
, nfp
.fraction
.value
);
265 ck_assert_str_eq(fp_fptostr(nfp
, NULL
), "14.5");
272 fixedpoint_suite(void)
274 Suite
*s
= suite_create("Fixed point representation");
276 #ifdef ENABLE_LLDPMED
277 TCase
*tc_fp
= tcase_create("Fixed point representation");
278 tcase_add_test(tc_fp
, test_string_parsing_suffix
);
279 tcase_add_test(tc_fp
, test_string_parsing_positive_int
);
280 tcase_add_test(tc_fp
, test_string_parsing_negative_int
);
281 tcase_add_test(tc_fp
, test_string_parsing_no_fract_part
);
282 tcase_add_test(tc_fp
, test_string_parsing_no_int_part
);
283 tcase_add_test(tc_fp
, test_string_parsing_positive_int_overflow
);
284 tcase_add_test(tc_fp
, test_string_parsing_negative_int_overflow
);
285 tcase_add_test(tc_fp
, test_string_parsing_positive_float
);
286 tcase_add_test(tc_fp
, test_string_parsing_negative_float
);
287 tcase_add_test(tc_fp
, test_string_representation_positive_int
);
288 tcase_add_test(tc_fp
, test_string_representation_negative_int
);
289 tcase_add_test(tc_fp
, test_string_representation_positive_float
);
290 tcase_add_test(tc_fp
, test_string_representation_positive_float_with_leading_zero
);
291 tcase_add_test(tc_fp
, test_string_representation_negative_float
);
292 tcase_add_test(tc_fp
, test_buffer_representation_positive_float
);
293 tcase_add_test(tc_fp
, test_buffer_representation_negative_float
);
294 tcase_add_test(tc_fp
, test_buffer_representation_with_shift
);
295 tcase_add_test(tc_fp
, test_buffer_representation_altitude
);
296 tcase_add_test(tc_fp
, test_buffer_parsing_positive_float
);
297 tcase_add_test(tc_fp
, test_buffer_parsing_positive_float_2
);
298 tcase_add_test(tc_fp
, test_buffer_parsing_negative_float
);
299 tcase_add_test(tc_fp
, test_buffer_parsing_positive_float_with_shift
);
300 tcase_add_test(tc_fp
, test_buffer_parsing_negative_float_with_shift
);
301 tcase_add_test(tc_fp
, test_negate_positive
);
302 tcase_add_test(tc_fp
, test_negate_negative
);
303 suite_add_tcase(s
, tc_fp
);
309 /* Disable leak detection sanitizer */
310 int __lsan_is_turned_off() {
318 Suite
*s
= fixedpoint_suite();
319 SRunner
*sr
= srunner_create(s
);
320 srunner_run_all(sr
, CK_ENV
);
321 number_failed
= srunner_ntests_failed(sr
);
323 return (number_failed
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;