1/*
2 * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3 *
4 * libcbor is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
6 */
7
8#include <math.h>
9#include "assertions.h"
10#include "cbor.h"
11
12unsigned char buffer[512];
13
14static void test_bools(void **_CBOR_UNUSED(_state)) {
15  assert_size_equal(1, cbor_encode_bool(false, buffer, 512));
16  assert_memory_equal(buffer, ((unsigned char[]){0xF4}), 1);
17  assert_size_equal(1, cbor_encode_bool(true, buffer, 512));
18  assert_memory_equal(buffer, ((unsigned char[]){0xF5}), 1);
19}
20
21static void test_null(void **_CBOR_UNUSED(_state)) {
22  assert_size_equal(1, cbor_encode_null(buffer, 512));
23  assert_memory_equal(buffer, ((unsigned char[]){0xF6}), 1);
24}
25
26static void test_undef(void **_CBOR_UNUSED(_state)) {
27  assert_size_equal(1, cbor_encode_undef(buffer, 512));
28  assert_memory_equal(buffer, ((unsigned char[]){0xF7}), 1);
29}
30
31static void test_break(void **_CBOR_UNUSED(_state)) {
32  assert_size_equal(1, cbor_encode_break(buffer, 512));
33  assert_memory_equal(buffer, ((unsigned char[]){0xFF}), 1);
34}
35
36/* Check that encode(decode(buffer)) = buffer for a valid half-float in the
37 * buffer.*/
38static void assert_half_float_codec_identity(void) {
39  unsigned char secondary_buffer[3];
40  struct cbor_load_result res;
41  // Load and check data in buffer
42  cbor_item_t *half_float = cbor_load(buffer, 3, &res);
43  assert_size_equal(res.error.code, CBOR_ERR_NONE);
44  assert_true(cbor_isa_float_ctrl(half_float));
45  assert_true(cbor_is_float(half_float));
46  assert_size_equal(cbor_float_get_width(half_float), CBOR_FLOAT_16);
47  // Encode again and check equality
48  assert_size_equal(3, cbor_encode_half(cbor_float_get_float2(half_float),
49                                        secondary_buffer, 3));
50  assert_memory_equal(buffer, secondary_buffer, 3);
51  cbor_decref(&half_float);
52}
53
54static void test_half(void **_CBOR_UNUSED(_state)) {
55  assert_size_equal(3, cbor_encode_half(1.5f, buffer, 512));
56  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x3E, 0x00}), 3);
57  assert_half_float_codec_identity();
58
59  assert_size_equal(3, cbor_encode_half(-0.0f, buffer, 512));
60  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x80, 0x00}), 3);
61  assert_half_float_codec_identity();
62
63  assert_size_equal(3, cbor_encode_half(0.0f, buffer, 512));
64  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x00}), 3);
65  assert_half_float_codec_identity();
66
67  assert_size_equal(3, cbor_encode_half(65504.0f, buffer, 512));
68  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7B, 0xFF}), 3);
69  assert_half_float_codec_identity();
70
71  assert_size_equal(3, cbor_encode_half(0.00006103515625f, buffer, 512));
72  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x04, 0x00}), 3);
73  assert_half_float_codec_identity();
74
75  assert_size_equal(3, cbor_encode_half(-4.0f, buffer, 512));
76  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0xC4, 0x00}), 3);
77  assert_half_float_codec_identity();
78
79  /* Smallest representable value */
80  assert_size_equal(3, cbor_encode_half(5.960464477539063e-8f, buffer, 512));
81  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x01}), 3);
82  assert_half_float_codec_identity();
83
84  /* Smaller than the smallest, approximate magnitude representation */
85  assert_size_equal(3, cbor_encode_half(5.960464477539062e-8f, buffer, 512));
86  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x01}), 3);
87  assert_half_float_codec_identity();
88
89  assert_size_equal(3, cbor_encode_half(4.172325134277344e-7f, buffer, 512));
90  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x07}), 3);
91  assert_half_float_codec_identity();
92
93  assert_size_equal(3, cbor_encode_half(6.097555160522461e-5f, buffer, 512));
94  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x03, 0xff}), 3);
95  assert_half_float_codec_identity();
96
97  assert_size_equal(3, cbor_encode_half(6.100535392761231e-5f, buffer, 512));
98  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x04, 0x00}), 3);
99  assert_half_float_codec_identity();
100
101  /* Smaller than the smallest and even the magnitude cannot be represented,
102     round off to zero */
103  assert_size_equal(3, cbor_encode_half(1e-25f, buffer, 512));
104  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x00}), 3);
105  assert_half_float_codec_identity();
106
107  assert_size_equal(3, cbor_encode_half(1.1920928955078125e-7, buffer, 512));
108  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x02}), 3);
109  assert_half_float_codec_identity();
110
111  assert_size_equal(3, cbor_encode_half(-1.1920928955078124e-7, buffer, 512));
112  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x80, 0x02}), 3);
113  assert_half_float_codec_identity();
114
115  assert_size_equal(3, cbor_encode_half(INFINITY, buffer, 512));
116  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7C, 0x00}), 3);
117  assert_half_float_codec_identity();
118}
119
120static void test_half_special(void **_CBOR_UNUSED(_state)) {
121  assert_size_equal(3, cbor_encode_half(NAN, buffer, 512));
122  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7E, 0x00}), 3);
123  assert_half_float_codec_identity();
124
125  // We discard all information bits in half-float NaNs. This is
126  // not required for the core CBOR protocol (it is only a suggestion in
127  // Section 3.9).
128  // See https://github.com/PJK/libcbor/issues/215
129  assert_size_equal(3, cbor_encode_half(nanf("2"), buffer, 512));
130  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7E, 0x00}), 3);
131  assert_half_float_codec_identity();
132}
133
134static void test_half_infinity(void **_CBOR_UNUSED(_state)) {
135  assert_size_equal(3, cbor_encode_half(INFINITY, buffer, 512));
136  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7C, 0x00}), 3);
137  assert_half_float_codec_identity();
138
139  assert_size_equal(3, cbor_encode_half(-INFINITY, buffer, 512));
140  assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0xFC, 0x00}), 3);
141  assert_half_float_codec_identity();
142}
143
144static void test_float(void **_CBOR_UNUSED(_state)) {
145  assert_size_equal(5, cbor_encode_single(3.4028234663852886e+38, buffer, 512));
146  assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0x7F, 0xFF, 0xFF}),
147                      5);
148
149  assert_size_equal(5, cbor_encode_single(NAN, buffer, 512));
150  assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0xC0, 0x00, 0x00}),
151                      5);
152
153#ifndef _WIN32
154  // TODO: https://github.com/PJK/libcbor/issues/271
155  assert_size_equal(5, cbor_encode_single(nanf("3"), buffer, 512));
156  assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0xC0, 0x00, 0x03}),
157                      5);
158#endif
159
160  assert_size_equal(5, cbor_encode_single(strtof("Inf", NULL), buffer, 512));
161  assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0x80, 0x00, 0x00}),
162                      5);
163
164  assert_size_equal(5, cbor_encode_single(strtof("-Inf", NULL), buffer, 512));
165  assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0xFF, 0x80, 0x00, 0x00}),
166                      5);
167}
168
169static void test_double(void **_CBOR_UNUSED(_state)) {
170  assert_size_equal(9, cbor_encode_double(1.0e+300, buffer, 512));
171  assert_memory_equal(
172      buffer,
173      ((unsigned char[]){0xFB, 0x7E, 0x37, 0xE4, 0x3C, 0x88, 0x00, 0x75, 0x9C}),
174      9);
175
176  assert_size_equal(9, cbor_encode_double(nan(""), buffer, 512));
177  assert_memory_equal(
178      buffer,
179      ((unsigned char[]){0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
180      9);
181
182#ifndef _WIN32
183  // TODO: https://github.com/PJK/libcbor/issues/271
184  assert_size_equal(9, cbor_encode_double(nan("3"), buffer, 512));
185  assert_memory_equal(
186      buffer,
187      ((unsigned char[]){0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}),
188      9);
189#endif
190
191  assert_size_equal(9, cbor_encode_double(strtod("Inf", NULL), buffer, 512));
192  assert_memory_equal(
193      buffer,
194      ((unsigned char[]){0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
195      9);
196
197  assert_size_equal(9, cbor_encode_double(strtod("-Inf", NULL), buffer, 512));
198  assert_memory_equal(
199      buffer,
200      ((unsigned char[]){0xFB, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
201      9);
202}
203
204int main(void) {
205  const struct CMUnitTest tests[] = {
206      cmocka_unit_test(test_bools),         cmocka_unit_test(test_null),
207      cmocka_unit_test(test_undef),         cmocka_unit_test(test_break),
208      cmocka_unit_test(test_half),          cmocka_unit_test(test_float),
209      cmocka_unit_test(test_double),        cmocka_unit_test(test_half_special),
210      cmocka_unit_test(test_half_infinity),
211  };
212  return cmocka_run_group_tests(tests, NULL, NULL);
213}
214