Browse Source
This is a malloc-free implementation of the Concise Binary Object Representation (CBOR) data format for the RIOT-OS. This implementation mostly stand-alone, and it should be pretty easy to port to other platforms. We're only using the C STL and some custom network-related functionaliy which could be easily replaced by depending on arpa/inet.h. The CBOR API is straight-forward to use and provides encoding/decoding functionality for all major C types, such as: - int - uint64_t - int64_t - float - double - char* - struct tm - time_t It is possible to conditionally compile this module via CFLAGS: - CBOR_NO_SEMANTIC_TAGGING: All semantic-tagging features removed - CBOR_NO_CTIME: All ctime related features removed - CBOR_NO_FLOAT: All floating-point related features removed - CBOR_NO_PRINT: All features depending on printf removeddev/timer

9 changed files with 2195 additions and 0 deletions
@ -0,0 +1,10 @@
|
||||
MODULE = cbor
|
||||
|
||||
CFLAGS += -DCBOR_NO_PRINT
|
||||
|
||||
ifeq (,$(filter native,$(BOARD))) |
||||
# build the minimal subset for non-native
|
||||
CFLAGS += -DCBOR_NO_FLOAT -DCBOR_NO_PRINT -DCBOR_NO_SEMANTIC_TAGGING
|
||||
endif |
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin |
||||
* Copyright (C) 2014 Kevin Funk <kfunk@kde.org> |
||||
* Copyright (C) 2014 Jana Cavojska <jana.cavojska9@gmail.com> |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser General |
||||
* Public License. See the file LICENSE in the top level directory for more |
||||
* details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cbor |
||||
* @{ |
||||
*/ |
||||
|
||||
/**
|
||||
* @file |
||||
* @brief Implementation of a CBOR serializer/deserializer in C |
||||
* |
||||
* @author Kevin Funk <kfunk@kde.org> |
||||
* @author Jana Cavojska <jana.cavojska9@gmail.com> |
||||
* |
||||
* This is an implementation suited for constrained devices |
||||
* Characteristics: |
||||
* - No dynamic memory allocation (i.e. no calls to @e malloc, @e free) used throughout the implementation |
||||
* - User may allocate static buffers, this implementation uses the space provided by them (cf. @ref cbor_stream_t) |
||||
* |
||||
* @par Supported types (categorized by major type (MT)): |
||||
* |
||||
* - Major type 0 (unsigned integer): Full support. Relevant functions: |
||||
* - cbor_serialize_int(), cbor_deserialize_int() |
||||
* - cbor_serialize_uint64_t(), cbor_deserialize_uint64_t() |
||||
* |
||||
* - Major type 1 (negative integer): Full support. Relevant functions: |
||||
* - cbor_serialize_int(), cbor_deserialize_int() |
||||
* - cbor_serialize_int64_t(), cbor_deserialize_int64_t() |
||||
* |
||||
* - Major type 2 (byte string): Full support. Relevant functions: |
||||
* - cbor_serialize_byte_string(), cbor_deserialize_byte_string() |
||||
* |
||||
* - Major type 3 (unicode string): Basic support (see below). Relevant functions: |
||||
* - cbor_serialize_unicode_string(), cbor_deserialize_unicode_string() |
||||
* |
||||
* - Major type 4 (array of data items): Full support. Relevant functions: |
||||
* - cbor_serialize_array(), cbor_deserialize_array() |
||||
* - cbor_serialize_indefinite_array(), cbor_deserialize_indefinite_array(), cbor_at_break() |
||||
* |
||||
* - Major type 5 (map of pairs of data items): Full support. Relevant functions: |
||||
* - cbor_serialize_map(), cbor_deserialize_map() |
||||
* - cbor_serialize_indefinite_map(), cbor_deserialize_indefinite_map(), cbor_at_break() |
||||
* |
||||
* - Major type 6 (optional semantic tagging of other major types): Basic support (see below). Relevant functions: |
||||
* - cbor_write_tag() |
||||
* - cbor_deserialize_date_time() |
||||
* - cbor_serialize_date_time() |
||||
* |
||||
* - Major type 7 (floating-point numbers and values with no content): Basic support (see below). Relevant functions: |
||||
* - cbor_serialize_float_half(), cbor_deserialize_float_half() |
||||
* - cbor_serialize_float(), cbor_deserialize_float() |
||||
* - cbor_serialize_double(), cbor_deserialize_double() |
||||
* - cbor_serialize_bool(), cbor_deserialize_bool() |
||||
* |
||||
* @par Notes about major type 3: |
||||
* Since we do not have a standardised C type for representing Unicode code points, |
||||
* we just provide API to serialize/deserialize @e char* arrays. The user then |
||||
* has to transform that into a meaningful representation |
||||
* |
||||
* @par Notes about major type 6 (cf. https://tools.ietf.org/html/rfc7049#section-2.4):
|
||||
* Encoding date and time: date/time strings that follow the standard format described in Section 3.3 of [RFC3339]: |
||||
* 2003-12-13T18:30:02Z - supported |
||||
* 2003-12-13T18:30:02.25Z - not supported |
||||
* 2003-12-13T18:30:02+01:00 - not supported |
||||
* 2003-12-13T18:30:02.25+01:00 - not supported |
||||
* Since we do not have C types for representing bignums/bigfloats/decimal-fraction |
||||
* we do not provide API to serialize/deserialize them at all. |
||||
* You can still read out the actual data item behind the tag (via cbor_deserialize_byte_string()) |
||||
* and interpret it yourself. |
||||
* |
||||
* @par Notes about major type 7 and simple values (cf. https://tools.ietf.org/html/rfc7049#section-2.3)
|
||||
* Simple values: |
||||
* - 0-19: (Unassigned) - No support |
||||
* - 20,21: True, False - Supported (see cbor_serialize_bool(), cbor_deserialize_bool()) |
||||
* - 22,23: Null, Undefined - No support (what's the use-case?) |
||||
* - 24-31: (Reserved) - No support |
||||
* - 32-255: (Unassigned) - No support |
||||
* |
||||
* TODO: API for Indefinite-Length Byte Strings and Text Strings |
||||
* (see https://tools.ietf.org/html/rfc7049#section-2.2.2)
|
||||
*/ |
||||
|
||||
#ifndef CBOR_H |
||||
#define CBOR_H |
||||
|
||||
#ifndef CBOR_NO_CTIME |
||||
/* 'strptime' is only declared when this macro is defined */ |
||||
#define _XOPEN_SOURCE |
||||
#endif |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#ifndef CBOR_NO_CTIME |
||||
#include <time.h> |
||||
#endif /* CBOR_NO_CTIME */ |
||||
|
||||
/**
|
||||
* @brief Struct containing CBOR-encoded data |
||||
* |
||||
* A typical usage of CBOR looks like: |
||||
* @code |
||||
* unsigned char data[1024]; |
||||
* cbor_stream_t stream; |
||||
* cbor_init(&stream, data, sizeof(data)); |
||||
* |
||||
* cbor_serialize_int(&stream, 5); |
||||
* (...) |
||||
* <data contains CBOR encoded items now> |
||||
* |
||||
* cbor_destroy(&stream); |
||||
* @endcode |
||||
* |
||||
* @sa cbor_init |
||||
* @sa cbor_clear |
||||
* @sa cbor_destroy |
||||
*/ |
||||
typedef struct cbor_stream_t { |
||||
/* Array containing CBOR encoded data */ |
||||
unsigned char *data; |
||||
/* Size of the array */ |
||||
size_t size; |
||||
/* Index to the next free byte */ |
||||
size_t pos; |
||||
} cbor_stream_t; |
||||
|
||||
/**
|
||||
* Initialize cbor struct |
||||
* |
||||
* @note Does *not* take ownership of @p buffer |
||||
* |
||||
* @param buffer The buffer used for storing CBOR-encoded data |
||||
* @param size The size of buffer @p buffer |
||||
*/ |
||||
void cbor_init(cbor_stream_t *stream, unsigned char *buffer, size_t size); |
||||
|
||||
/**
|
||||
* Clear cbor struct |
||||
* |
||||
* Sets pos to zero |
||||
*/ |
||||
void cbor_clear(cbor_stream_t *stream); |
||||
|
||||
/**
|
||||
* Destroy the cbor struct |
||||
* |
||||
* @note Does *not* free data |
||||
*/ |
||||
void cbor_destroy(cbor_stream_t *stream); |
||||
|
||||
#ifndef CBOR_NO_PRINT |
||||
/**
|
||||
* Print @p stream in hex representation |
||||
*/ |
||||
void cbor_stream_print(const cbor_stream_t *stream); |
||||
|
||||
/**
|
||||
* Decode CBOR from @p stream |
||||
* |
||||
* This method interprets the data and prints each item in its natural representation |
||||
* |
||||
* Example output: |
||||
* @code |
||||
* Data: |
||||
* (int, 1) |
||||
* (bool, 1) |
||||
* (float, 1.099609) |
||||
* (tag: 0, date/time string: "Mon Jul 14 19:07:40 2014") |
||||
* (tag: 1, date/time epoch: 1405357660) |
||||
* @endcode |
||||
*/ |
||||
void cbor_stream_decode(cbor_stream_t *stream); |
||||
#endif /* CBOR_NO_PRINT */ |
||||
|
||||
size_t cbor_serialize_int(cbor_stream_t *s, int val); |
||||
size_t cbor_deserialize_int(const cbor_stream_t *stream, size_t offset, int *val); |
||||
size_t cbor_serialize_uint64_t(cbor_stream_t *s, uint64_t val); |
||||
size_t cbor_deserialize_uint64_t(const cbor_stream_t *stream, size_t offset, uint64_t *val); |
||||
size_t cbor_serialize_int64_t(cbor_stream_t *s, int64_t val); |
||||
size_t cbor_deserialize_int64_t(const cbor_stream_t *stream, size_t offset, int64_t *val); |
||||
size_t cbor_serialize_bool(cbor_stream_t *s, bool val); |
||||
size_t cbor_deserialize_bool(const cbor_stream_t *stream, size_t offset, bool *val); |
||||
#ifndef CBOR_NO_FLOAT |
||||
size_t cbor_serialize_float_half(cbor_stream_t *s, float val); |
||||
size_t cbor_deserialize_float_half(const cbor_stream_t *stream, size_t offset, float *val); |
||||
size_t cbor_serialize_float(cbor_stream_t *s, float val); |
||||
size_t cbor_deserialize_float(const cbor_stream_t *stream, size_t offset, float *val); |
||||
size_t cbor_serialize_double(cbor_stream_t *s, double val); |
||||
size_t cbor_deserialize_double(const cbor_stream_t *stream, size_t offset, double *val); |
||||
#endif /* CBOR_NO_FLOAT */ |
||||
|
||||
size_t cbor_serialize_byte_string(cbor_stream_t *s, const char *val); |
||||
/**
|
||||
* Deserialize bytes from @p stream to @p val |
||||
* |
||||
* @param val Pointer to destination array |
||||
* @param length Length of destination array |
||||
* @return Number of bytes written into @p val |
||||
*/ |
||||
size_t cbor_deserialize_byte_string(const cbor_stream_t *stream, size_t offset, char *val, size_t length); |
||||
size_t cbor_serialize_unicode_string(cbor_stream_t *s, const char *val); |
||||
/**
|
||||
* Deserialize unicode string from @p stream to @p val |
||||
* |
||||
* @param val Pointer to destination array |
||||
* @param length Length of destination array |
||||
* @return Number of bytes written into @p val |
||||
*/ |
||||
size_t cbor_deserialize_unicode_string(const cbor_stream_t *stream, size_t offset, char *val, size_t length); |
||||
|
||||
/**
|
||||
* Serialize array of length @p array_length |
||||
* |
||||
* Basic usage: |
||||
* @code |
||||
* cbor_serialize_array(&stream, 2); // array of length 2 follows
|
||||
* cbor_serialize_int(&stream, 1)); // write item 1
|
||||
* cbor_serialize_int(&stream, 2)); // write item 2
|
||||
* @endcode |
||||
* |
||||
* @note You have to make sure to serialize the correct amount of items. |
||||
* If you exceed the length @p array_length, items will just be appened as normal |
||||
* |
||||
* @param array_length Length of the array of items which follows |
||||
* |
||||
* @return Number of bytes written to stream @p s |
||||
*/ |
||||
size_t cbor_serialize_array(cbor_stream_t *s, size_t array_length); |
||||
/**
|
||||
* Deserialize array of items |
||||
* |
||||
* Basic usage: |
||||
* @code |
||||
* size_t array_length; |
||||
* size_t offset = cbor_deserialize_array(&stream, 0, &array_length); // read out length of the array
|
||||
* int i1, i2; |
||||
* offset += cbor_deserialize_int(&stream, offset, &i1); // read item 1
|
||||
* offset += cbor_deserialize_int(&stream, offset, &i2); // read item 2
|
||||
* @endcode |
||||
* |
||||
* @param array_length Where the array length is stored |
||||
*/ |
||||
size_t cbor_deserialize_array(const cbor_stream_t *s, size_t offset, size_t *array_length); |
||||
|
||||
size_t cbor_serialize_array_indefinite(cbor_stream_t *s); |
||||
size_t cbor_deserialize_array_indefinite(const cbor_stream_t *s, size_t offset); |
||||
|
||||
/**
|
||||
* Serialize map of length @p map_length |
||||
* |
||||
* Basic usage: |
||||
* @code |
||||
* cbor_serialize_map(&stream, 2); // map of length 2 follows
|
||||
* cbor_serialize_int(&stream, 1)); // write key 1
|
||||
* cbor_serialize_byte_string(&stream, "1")); // write value 1
|
||||
* cbor_serialize_int(&stream, 2)); // write key 2
|
||||
* cbor_serialize_byte_string(&stream, "2")); // write value 2
|
||||
* @endcode |
||||
* |
||||
* @param map_length Length of the map of items which follows |
||||
*/ |
||||
size_t cbor_serialize_map(cbor_stream_t *s, size_t map_length); |
||||
/**
|
||||
* Deserialize map of items |
||||
* |
||||
* Basic usage: |
||||
* @code |
||||
* size_t map_length; |
||||
* size_t offset = cbor_deserialize_map(&stream, 0, &map_length); // read out length of the map
|
||||
* int key1, key1; |
||||
* char value1[8], value2[8]; |
||||
* offset += cbor_deserialize_int(&stream, offset, &key1); // read key 1
|
||||
* offset += cbor_deserialize_byte_string(&stream, offset, value1, sizeof(value)); // read value 1
|
||||
* offset += cbor_deserialize_int(&stream, offset, &key2); // read key 2
|
||||
* offset += cbor_deserialize_byte_string(&stream, offset, value2, sizeof(value)); // read value 2
|
||||
* @endcode |
||||
* |
||||
* @param array_length Where the array length is stored |
||||
*/ |
||||
size_t cbor_deserialize_map(const cbor_stream_t *s, size_t offset, size_t *map_length); |
||||
|
||||
size_t cbor_serialize_map_indefinite(cbor_stream_t *s); |
||||
size_t cbor_deserialize_map_indefinite(const cbor_stream_t *s, size_t offset); |
||||
|
||||
#ifndef CBOR_NO_SEMANTIC_TAGGING |
||||
#ifndef CBOR_NO_CTIME |
||||
/**
|
||||
* Serialize date and time |
||||
* |
||||
* Basic usage: |
||||
* @code |
||||
* struct tm val; |
||||
* val.tm_year = 114; |
||||
* val.tm_mon = 6; |
||||
* val.tm_mday = 1; |
||||
* val.tm_hour = 15; |
||||
* val.tm_min = 0; |
||||
* val.tm_sec = 0; |
||||
* mktime(&val); |
||||
* cbor_serialize_date_time(&stream, &val); |
||||
* @endcode |
||||
* |
||||
* @param val tm struct containing the date/time info to be encoded |
||||
*/ |
||||
size_t cbor_serialize_date_time(cbor_stream_t *stream, struct tm *val); |
||||
/**
|
||||
* Deserialize date and time |
||||
* |
||||
* Basic usage: |
||||
* @code |
||||
* struct tm val; |
||||
* cbor_deserialize_date_time(&stream, 0, &val); |
||||
* @endcode |
||||
* |
||||
* @param val tm struct where the decoded date/time will be stored |
||||
*/ |
||||
size_t cbor_deserialize_date_time(const cbor_stream_t *stream, size_t offset, struct tm *val); |
||||
|
||||
size_t cbor_serialize_date_time_epoch(cbor_stream_t *stream, time_t val); |
||||
size_t cbor_deserialize_date_time_epoch(const cbor_stream_t *stream, size_t offset, time_t *val); |
||||
#endif /* CBOR_NO_CTIME */ |
||||
|
||||
/**
|
||||
* Write a tag to give the next CBOR item additional semantics |
||||
* |
||||
* Also see https://tools.ietf.org/html/rfc7049#section-2.4 (Optional Tagging of Items)
|
||||
*/ |
||||
size_t cbor_write_tag(cbor_stream_t *s, unsigned char tag); |
||||
/**
|
||||
* Whether we are at a tag symbol in stream @p s at offset @p offset |
||||
* |
||||
* @return True in case there is a tag symbol at the current offset |
||||
*/ |
||||
bool cbor_at_tag(const cbor_stream_t *s, size_t offset); |
||||
/**
|
||||
* Write a break symbol at the current offset in stream @p s |
||||
* |
||||
* Used for marking the end of indefinite length CBOR items |
||||
*/ |
||||
#endif /* CBOR_NO_SEMANTIC_TAGGING */ |
||||
|
||||
size_t cbor_write_break(cbor_stream_t *s); |
||||
/**
|
||||
* Whether we are at a break symbol in stream @p s at offset @p offset |
||||
* |
||||
* @return True in case the there is a break symbol at the current offset |
||||
*/ |
||||
bool cbor_at_break(const cbor_stream_t *s, size_t offset); |
||||
/**
|
||||
* Whether we are at the end of the stream @p s at offset @p offset |
||||
* |
||||
* Useful for abort conditions in loops while deserializing CBOR items |
||||
* |
||||
* @return True in case @p offset marks the end of the stream |
||||
*/ |
||||
bool cbor_at_end(const cbor_stream_t *s, size_t offset); |
||||
|
||||
#endif |
||||
|
||||
/** @} */ |
@ -0,0 +1,9 @@
|
||||
MODULE = tests-cbor
|
||||
|
||||
CFLAGS += -DCBOR_NO_PRINT
|
||||
|
||||
ifeq (,$(filter native,$(BOARD))) |
||||
CFLAGS += -DCBOR_NO_FLOAT -DCBOR_NO_PRINT -DCBOR_NO_SEMANTIC_TAGGING
|
||||
endif |
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,790 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin |
||||
* Copyright (C) 2014 Kevin Funk <kfunk@kde.org> |
||||
* Copyright (C) 2014 Jana Cavojska <jana.cavojska9@gmail.com> |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser General |
||||
* Public License v2.1. See the file LICENSE in the top level directory for more |
||||
* details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @author Kevin Funk <kfunk@kde.org> |
||||
* @author Jana Cavojska <jana.cavojska9@gmail.com> |
||||
*/ |
||||
|
||||
#include "../unittests.h" |
||||
|
||||
#include "bitarithm.h" |
||||
#include "cbor.h" |
||||
|
||||
#include <float.h> |
||||
#include <math.h> |
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <inttypes.h> |
||||
#ifndef CBOR_NO_CTIME |
||||
#include <time.h> |
||||
#endif /* CBOR_NO_CTIME */ |
||||
|
||||
static void my_cbor_print(const cbor_stream_t *stream) |
||||
{ |
||||
#ifndef CBOR_NO_PRINT |
||||
cbor_stream_print(stream); |
||||
#else |
||||
printf("<no print support>"); |
||||
#endif |
||||
} |
||||
|
||||
#define CBOR_CHECK_SERIALIZED(stream, expected_value, expected_value_size) do { \ |
||||
if (memcmp(stream.data, expected_value, expected_value_size) != 0) { \
|
||||
printf("\n"); \
|
||||
printf(" CBOR encoded data: "); my_cbor_print(&stream); printf("\n"); \
|
||||
cbor_stream_t tmp = {expected_value, expected_value_size, expected_value_size}; \
|
||||
printf(" Expected data : "); my_cbor_print(&tmp); printf("\n"); \
|
||||
TEST_FAIL("Test failed"); \
|
||||
} \
|
||||
} while(0) |
||||
|
||||
#define CBOR_CHECK_DESERIALIZED(expected_value, actual_value, comparator_function) do { \ |
||||
TEST_ASSERT(comparator_function(expected_value, actual_value)); \
|
||||
} while(0) |
||||
|
||||
/* Macro for checking PODs (int, float, ...) */ |
||||
#define CBOR_CHECK(type, function_suffix, stream, input, expected_value, comparator) do { \ |
||||
type buffer; \
|
||||
unsigned char data[] = expected_value; \
|
||||
cbor_clear(&stream); \
|
||||
TEST_ASSERT(cbor_serialize_##function_suffix(&stream, input)); \
|
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); \
|
||||
cbor_stream_t tmp = {data, sizeof(data), sizeof(data)}; \
|
||||
TEST_ASSERT(cbor_deserialize_##function_suffix(&tmp, 0, &buffer)); \
|
||||
CBOR_CHECK_DESERIALIZED(input, buffer, comparator); \
|
||||
} while(0) |
||||
|
||||
#define HEX_LITERAL(...) {__VA_ARGS__} |
||||
|
||||
/* BEGIN: Comparator functions */ |
||||
#define EQUAL_INT(a, b) \ |
||||
(a == b) |
||||
#define EQUAL_FLOAT(a, b) ( \ |
||||
(isinf(a) && isinf(b)) || \
|
||||
(isnan(a) && isnan(b)) || \
|
||||
(fabs(a - b) < 0.00001)) |
||||
#define EQUAL_STRING(a, b) \ |
||||
(strcmp(a, b) == 0) |
||||
#define EQUAL_DATE_TIME(a, b) ( \ |
||||
(a.tm_isdst == b.tm_isdst) && \
|
||||
(a.tm_yday == b.tm_yday) && \
|
||||
(a.tm_wday == b.tm_wday) && \
|
||||
(a.tm_year == b.tm_year) && \
|
||||
(a.tm_mon == b.tm_mon) && \
|
||||
(a.tm_mday == b.tm_mday) && \
|
||||
(a.tm_hour == b.tm_hour) && \
|
||||
(a.tm_min == b.tm_min) && \
|
||||
(a.tm_sec == b.tm_sec)) |
||||
/* END: Comparator functions */ |
||||
|
||||
#ifndef INFINITY |
||||
#define INFINITY (1.0/0.0) |
||||
#endif |
||||
#ifndef NAN |
||||
#define NAN (0.0/0.0) |
||||
#endif |
||||
|
||||
static unsigned char stream_data[1024]; |
||||
cbor_stream_t stream = {stream_data, sizeof(stream_data), 0}; |
||||
|
||||
cbor_stream_t empty_stream = {NULL, 0, 0}; /* stream that is not large enough */ |
||||
|
||||
unsigned char invalid_stream_data[] = {0x40}; /* empty string encoded in CBOR */ |
||||
cbor_stream_t invalid_stream = {invalid_stream_data, sizeof(invalid_stream_data), |
||||
sizeof(invalid_stream_data) |
||||
}; |
||||
|
||||
static void setUp(void) |
||||
{ |
||||
cbor_clear(&stream); |
||||
} |
||||
|
||||
static void tearDown(void) |
||||
{ |
||||
} |
||||
|
||||
static void test_int(void) |
||||
{ |
||||
/* positive values */ |
||||
CBOR_CHECK(int, int, stream, 0, HEX_LITERAL(0x00), EQUAL_INT); |
||||
CBOR_CHECK(int, int, stream, 23, HEX_LITERAL(0x17), EQUAL_INT); |
||||
|
||||
CBOR_CHECK(int, int, stream, 24, HEX_LITERAL(0x18, 0x18), EQUAL_INT); |
||||
CBOR_CHECK(int, int, stream, 0xff, HEX_LITERAL(0x18, 0xff), EQUAL_INT); |
||||
|
||||
CBOR_CHECK(int, int, stream, 0xff + 1, HEX_LITERAL(0x19, 0x01, 0x00), EQUAL_INT); |
||||
CBOR_CHECK(int, int, stream, 0xffff, HEX_LITERAL(0x19, 0xff, 0xff), EQUAL_INT); |
||||
|
||||
CBOR_CHECK(int, int, stream, 0xffff + 1, |
||||
HEX_LITERAL(0x1a, 0x00, 0x01, 0x00, 0x00), EQUAL_INT); |
||||
#if ARCH_32_BIT |
||||
CBOR_CHECK(int, int, stream, 0x7fffffff, |
||||
HEX_LITERAL(0x1a, 0x7f, 0xff, 0xff, 0xff), EQUAL_INT); |
||||
#endif |
||||
|
||||
/* negative values */ |
||||
CBOR_CHECK(int, int, stream, -1, HEX_LITERAL(0x20), EQUAL_INT); |
||||
CBOR_CHECK(int, int, stream, -24, HEX_LITERAL(0x37), EQUAL_INT); |
||||
|
||||
CBOR_CHECK(int, int, stream, -25, HEX_LITERAL(0x38, 0x18), EQUAL_INT); |
||||
CBOR_CHECK(int, int, stream, -0xff - 1, HEX_LITERAL(0x38, 0xff), EQUAL_INT); |
||||
|
||||
CBOR_CHECK(int, int, stream, -0xff - 2, HEX_LITERAL(0x39, 0x01, 0x00), EQUAL_INT); |
||||
CBOR_CHECK(int, int, stream, -0xffff - 1, HEX_LITERAL(0x39, 0xff, 0xff), EQUAL_INT); |
||||
|
||||
CBOR_CHECK(int, int, stream, -0xffff - 2, |
||||
HEX_LITERAL(0x3a, 0x00, 0x01, 0x00, 0x00), EQUAL_INT); |
||||
#if ARCH_32_BIT |
||||
CBOR_CHECK(int, int, stream, -0x7fffffff - 1, |
||||
HEX_LITERAL(0x3a, 0x7f, 0xff, 0xff, 0xff), EQUAL_INT); |
||||
#endif |
||||
} |
||||
|
||||
static void test_uint64_t(void) |
||||
{ |
||||
CBOR_CHECK(uint64_t, uint64_t, stream, 0x0, |
||||
HEX_LITERAL(0x00), EQUAL_INT); |
||||
CBOR_CHECK(uint64_t, uint64_t, stream, 0xff, |
||||
HEX_LITERAL(0x18, 0xff), EQUAL_INT); |
||||
CBOR_CHECK(uint64_t, uint64_t, stream, 0xffff, |
||||
HEX_LITERAL(0x19, 0xff, 0xff), EQUAL_INT); |
||||
|
||||
CBOR_CHECK(uint64_t, uint64_t, stream, 0xffffffffull, |
||||
HEX_LITERAL(0x1a, 0xff, 0xff, 0xff, 0xff), EQUAL_INT); |
||||
CBOR_CHECK(uint64_t, uint64_t, stream, 0xffffffffffffffffull, |
||||
HEX_LITERAL(0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), EQUAL_INT); |
||||
} |
||||
|
||||
static void test_int_invalid(void) |
||||
{ |
||||
{ |
||||
/* check writing to stream that is not large enough */ |
||||
/* basically tests internal 'encode_int' function */ |
||||
|
||||
cbor_stream_t stream; |
||||
cbor_init(&stream, 0, 0); |
||||
|
||||
/* check each possible branch in 'encode_int' */ |
||||
/* (value in first byte, uint8 follows, uint16 follows, uint64 follows) */ |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int(&stream, 0)); |
||||
TEST_ASSERT_EQUAL_INT(0, stream.pos); |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int(&stream, 24)); |
||||
TEST_ASSERT_EQUAL_INT(0, stream.pos); |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int(&stream, 0xff + 1)); |
||||
TEST_ASSERT_EQUAL_INT(0, stream.pos); |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int(&stream, 0xffff + 1)); |
||||
TEST_ASSERT_EQUAL_INT(0, stream.pos); |
||||
} |
||||
|
||||
{ |
||||
/* check reading from stream that contains other type of data */ |
||||
|
||||
int val_int = 0; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_int(&invalid_stream, 0, &val_int)); |
||||
} |
||||
} |
||||
|
||||
static void test_uint64_t_invalid(void) |
||||
{ |
||||
{ |
||||
cbor_stream_t stream; |
||||
cbor_init(&stream, 0, 0); |
||||
|
||||
/* let's do this for 'cbor_serialize_int64_t', too */ |
||||
/* this uses 'encode_int' internally, as well, so let's just test if the */ |
||||
/* 'cbor_serialize_int64_t' wrapper is sane */ |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_uint64_t(&stream, 0)); |
||||
TEST_ASSERT_EQUAL_INT(0, stream.pos); |
||||
} |
||||
|
||||
{ |
||||
/* check reading from stream that contains other type of data */ |
||||
unsigned char data[] = {0x40}; /* empty string encoded in CBOR */ |
||||
cbor_stream_t stream = {data, 1, 1}; |
||||
uint64_t val_uint64_t = 0; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_uint64_t(&stream, 0, &val_uint64_t)); |
||||
} |
||||
} |
||||
|
||||
static void test_int64_t(void) |
||||
{ |
||||
CBOR_CHECK(int64_t, int64_t, stream, -1, |
||||
HEX_LITERAL(0x20), EQUAL_INT); |
||||
CBOR_CHECK(int64_t, int64_t, stream, -0xff - 1, |
||||
HEX_LITERAL(0x38, 0xff), EQUAL_INT); |
||||
CBOR_CHECK(int64_t, int64_t, stream, -0xffff - 1, |
||||
HEX_LITERAL(0x39, 0xff, 0xff), EQUAL_INT); |
||||
CBOR_CHECK(int64_t, int64_t, stream, -0xffffffffll - 1, |
||||
HEX_LITERAL(0x3a, 0xff, 0xff, 0xff, 0xff), EQUAL_INT); |
||||
CBOR_CHECK(int64_t, int64_t, stream, -0x7fffffffffffffffll - 1, |
||||
HEX_LITERAL(0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), EQUAL_INT); |
||||
} |
||||
|
||||
static void test_int64_t_invalid(void) |
||||
{ |
||||
{ |
||||
/* check writing to stream that is not large enough (also see test_major_type_0_invalid) */ |
||||
|
||||
cbor_stream_t stream; |
||||
cbor_init(&stream, 0, 0); |
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int64_t(&stream, 0)); |
||||
TEST_ASSERT_EQUAL_INT(0, stream.pos); |
||||
} |
||||
|
||||
{ |
||||
/* check reading from stream that contains other type of data */ |
||||
|
||||
unsigned char data[] = {0x40}; /* empty string encoded in CBOR */ |
||||
cbor_stream_t stream = {data, 1, 1}; |
||||
|
||||
int64_t val = 0; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_int64_t(&stream, 0, &val)); |
||||
} |
||||
} |
||||
|
||||
static void test_byte_string(void) |
||||
{ |
||||
char buffer[128]; |
||||
|
||||
{ |
||||
const char *input = ""; |
||||
unsigned char data[] = {0x40}; |
||||
TEST_ASSERT(cbor_serialize_byte_string(&stream, input)); |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
TEST_ASSERT(cbor_deserialize_byte_string(&stream, 0, buffer, sizeof(buffer))); |
||||
CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING); |
||||
} |
||||
|
||||
cbor_clear(&stream); |
||||
|
||||
{ |
||||
const char *input = "a"; |
||||
unsigned char data[] = {0x41, 0x61}; |
||||
TEST_ASSERT(cbor_serialize_byte_string(&stream, input)); |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
TEST_ASSERT(cbor_deserialize_byte_string(&stream, 0, buffer, sizeof(buffer))); |
||||
CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING); |
||||
} |
||||
} |
||||
|
||||
static void test_byte_string_invalid(void) |
||||
{ |
||||
{ |
||||
/* check writing to stream that is not large enough */ |
||||
cbor_stream_t stream; |
||||
cbor_init(&stream, 0, 0); |
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_byte_string(&stream, "foo")); |
||||
|
||||
cbor_destroy(&stream); |
||||
} |
||||
} |
||||
|
||||
|
||||
static void test_unicode_string(void) |
||||
{ |
||||
char buffer[128]; |
||||
|
||||
{ |
||||
const char *input = ""; |
||||
unsigned char data[] = {0x60}; |
||||
TEST_ASSERT(cbor_serialize_unicode_string(&stream, input)); |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
TEST_ASSERT(cbor_deserialize_unicode_string(&stream, 0, buffer, sizeof(buffer))); |
||||
CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING); |
||||
} |
||||
|
||||
cbor_clear(&stream); |
||||
|
||||
{ |
||||
const char *input = "a"; |
||||
unsigned char data[] = {0x61, 0x61}; |
||||
TEST_ASSERT(cbor_serialize_unicode_string(&stream, input)); |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
TEST_ASSERT(cbor_deserialize_unicode_string(&stream, 0, buffer, sizeof(buffer))); |
||||
CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING); |
||||
} |
||||
} |
||||
|
||||
static void test_unicode_string_invalid(void) |
||||
{ |
||||
{ |
||||
/* check writing to stream that is not large enough */ |
||||
cbor_stream_t stream; |
||||
cbor_init(&stream, 0, 0); |
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_unicode_string(&stream, "foo")); |
||||
|
||||
cbor_destroy(&stream); |
||||
} |
||||
} |
||||
|
||||
static void test_array(void) |
||||
{ |
||||
/* uniform types */ |
||||
{ |
||||
/* serialization */ |
||||
TEST_ASSERT(cbor_serialize_array(&stream, 2)); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 1)); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 2)); |
||||
unsigned char data[] = {0x82, 0x01, 0x02}; |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
|
||||
/* deserialization */ |
||||
size_t array_length; |
||||
size_t offset = cbor_deserialize_array(&stream, 0, &array_length); |
||||
TEST_ASSERT_EQUAL_INT(2, array_length); |
||||
int i; |
||||
offset += cbor_deserialize_int(&stream, offset, &i); |
||||
TEST_ASSERT_EQUAL_INT(1, i); |
||||
offset += cbor_deserialize_int(&stream, offset, &i); |
||||
TEST_ASSERT_EQUAL_INT(2, i); |
||||
} |
||||
|
||||
cbor_clear(&stream); |
||||
|
||||
/* mixed types */ |
||||
{ |
||||
TEST_ASSERT(cbor_serialize_array(&stream, 2)); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 1)); |
||||
TEST_ASSERT(cbor_serialize_byte_string(&stream, "a")); |
||||
unsigned char data[] = {0x82, 0x01, 0x41, 0x61}; |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
|
||||
/* deserialization */ |
||||
size_t array_length; |
||||
size_t offset = cbor_deserialize_array(&stream, 0, &array_length); |
||||
TEST_ASSERT(offset); |
||||
TEST_ASSERT_EQUAL_INT(2, array_length); |
||||
int i; |
||||
offset += cbor_deserialize_int(&stream, offset, &i); |
||||
TEST_ASSERT_EQUAL_INT(1, i); |
||||
char buffer[1024]; |
||||
offset += cbor_deserialize_byte_string(&stream, offset, buffer, sizeof(buffer)); |
||||
TEST_ASSERT_EQUAL_STRING("a", buffer); |
||||
} |
||||
} |
||||
|
||||
static void test_array_indefinite(void) |
||||
{ |
||||
{ |
||||
/* serialization */ |
||||
TEST_ASSERT(cbor_serialize_array_indefinite(&stream)); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 1)); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 2)); |
||||
TEST_ASSERT(cbor_write_break(&stream)); |
||||
unsigned char data[] = {0x9f, 0x01, 0x02, 0xff}; |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
|
||||
/* deserialization */ |
||||
size_t offset = cbor_deserialize_array_indefinite(&stream, 0); |
||||
int count = 0; |
||||
|
||||
while (!cbor_at_break(&stream, offset)) { |
||||
int val; |
||||
size_t read_bytes = cbor_deserialize_int(&stream, offset, &val); |
||||
TEST_ASSERT(read_bytes); |
||||
offset += read_bytes; |
||||
++count; |
||||
} |
||||
|
||||
TEST_ASSERT_EQUAL_INT(2, count); |
||||
TEST_ASSERT(cbor_at_end(&stream, offset)); |
||||
} |
||||
} |
||||
|
||||
static void test_array_invalid(void) |
||||
{ |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_array(&empty_stream, 1)); |
||||
|
||||
size_t array_length; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_array(&invalid_stream, 0, &array_length)); |
||||
} |
||||
|
||||
static void test_map(void) |
||||
{ |
||||
{ |
||||
/* serialization */ |
||||
TEST_ASSERT(cbor_serialize_map(&stream, 2)); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 1)); |
||||
TEST_ASSERT(cbor_serialize_byte_string(&stream, "1")); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 2)); |
||||
TEST_ASSERT(cbor_serialize_byte_string(&stream, "2")); |
||||
unsigned char data[] = {0xa2, |
||||
0x01, 0x41, 0x31, /* kv-pair 1 */ |
||||
0x02, 0x41, 0x32, /* kv-pair 2 */ |
||||
}; |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
|
||||
/* deserialization */ |
||||
size_t map_length; |
||||
size_t offset = cbor_deserialize_map(&stream, 0, &map_length); |
||||
TEST_ASSERT_EQUAL_INT(2, map_length); |
||||
int key; |
||||
char value[8]; |
||||
offset += cbor_deserialize_int(&stream, offset, &key); |
||||
TEST_ASSERT_EQUAL_INT(1, key); |
||||
offset += cbor_deserialize_byte_string(&stream, offset, value, sizeof(value)); |
||||
TEST_ASSERT_EQUAL_STRING("1", value); |
||||
offset += cbor_deserialize_int(&stream, offset, &key); |
||||
TEST_ASSERT_EQUAL_INT(2, key); |
||||
offset += cbor_deserialize_byte_string(&stream, offset, value, sizeof(value)); |
||||
TEST_ASSERT_EQUAL_STRING("2", value); |
||||
} |
||||
} |
||||
|
||||
static void test_map_indefinite(void) |
||||
{ |
||||
{ |
||||
/* serialization */ |
||||
TEST_ASSERT(cbor_serialize_map_indefinite(&stream)); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 1)); |
||||
TEST_ASSERT(cbor_serialize_byte_string(&stream, "1")); |
||||
TEST_ASSERT(cbor_serialize_int(&stream, 2)); |
||||
TEST_ASSERT(cbor_serialize_byte_string(&stream, "2")); |
||||
TEST_ASSERT(cbor_write_break(&stream)); |
||||
unsigned char data[] = {0xbf, |
||||
0x01, 0x41, 0x31, /* kv-pair 1 */ |
||||
0x02, 0x41, 0x32, /* kv-pair 2 */ |
||||
0xff |
||||
}; |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
|
||||
/* deserialization */ |
||||
size_t offset = cbor_deserialize_map_indefinite(&stream, 0); |
||||
int count = 0; |
||||
|
||||
while (!cbor_at_break(&stream, offset)) { |
||||
int key; |
||||
char value[16]; |
||||
size_t read_bytes; |
||||
offset += read_bytes = cbor_deserialize_int(&stream, offset, &key); |
||||
TEST_ASSERT(read_bytes); |
||||
offset += read_bytes = cbor_deserialize_byte_string(&stream, offset, |
||||
value, sizeof(value)); |
||||
TEST_ASSERT(read_bytes); |
||||
++count; |
||||
} |
||||
|
||||
TEST_ASSERT_EQUAL_INT(2, count); |
||||
TEST_ASSERT(cbor_at_end(&stream, offset)); |
||||
} |
||||
} |
||||
|
||||
static void test_map_invalid(void) |
||||
{ |
||||
{ |
||||
/* check writing to stream that is not large enough */ |
||||
cbor_stream_t stream; |
||||
cbor_init(&stream, 0, 0); |
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_map(&stream, 1)); |
||||
|
||||
cbor_destroy(&stream); |
||||
} |
||||
{ |
||||
/* check reading from stream that contains other type of data */ |
||||
unsigned char data[] = {0x40}; /* empty string encoded in CBOR */ |
||||
cbor_stream_t stream = {data, 1, 1}; |
||||
|
||||
size_t map_length; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_map(&stream, 0, &map_length)); |
||||
} |
||||
} |
||||
|
||||
#ifndef CBOR_NO_SEMANTIC_TAGGING |
||||
static void test_semantic_tagging(void) |
||||
{ |
||||
char buffer[128]; |
||||
{ |
||||
const char *input = "1"; |
||||
/* CBOR: byte string of length 1 marked with a tag to indicate it is a positive bignum */ |
||||
/* byte 1: (major type 6, additional information */ |
||||
/* byte 2: (major type 2, additional 1 for the length) */ |
||||
/* byte 3: bytes representing the bignum */ |
||||
unsigned char data[] = {0xc2, 0x41, 0x31}; |
||||
TEST_ASSERT(cbor_write_tag(&stream, 2)); /* write byte 1 */ |
||||
TEST_ASSERT(cbor_serialize_byte_string(&stream, input)); /* write byte 2 and 3 */ |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
TEST_ASSERT(cbor_at_tag(&stream, 0)); |
||||
TEST_ASSERT(cbor_deserialize_byte_string(&stream, 1, buffer, sizeof(buffer))); |
||||
CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING); |
||||
} |
||||
} |
||||
|
||||
#ifndef CBOR_NO_CTIME |
||||
static void test_date_time(void) |
||||
{ |
||||
/* CBOR: UTF-8 string marked with a tag 0 to indicate it is a standard date/time string */ |
||||
/* byte 1: (major type 6, additional information */ |
||||
/* byte 2: (major type 2, additional 23 for the length) */ |
||||
/* bytes 3 to 23: bytes representing the date/time UTF-8 string */ |
||||
unsigned char data[] = {0xC0, 0x74, 0x32, 0x30, 0x31, 0x34, 0x2D, 0x30, 0x37, 0x2D, 0x30, 0x31, |
||||
0x54, 0x31, 0x35, 0x3A, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x5A |
||||
}; |
||||
struct tm val; |
||||
val.tm_year = 114; |
||||
val.tm_mon = 6; |
||||
val.tm_mday = 1; |
||||
val.tm_hour = 15; |
||||
val.tm_min = 0; |
||||
val.tm_sec = 0; |
||||
mktime(&val); |
||||
TEST_ASSERT(cbor_serialize_date_time(&stream, &val)); |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
|
||||
TEST_ASSERT(cbor_at_tag(&stream, 0)); |
||||
struct tm val2; |
||||
TEST_ASSERT(cbor_deserialize_date_time(&stream, 0, &val2)); |
||||
CBOR_CHECK_DESERIALIZED(val, val2, EQUAL_DATE_TIME); |
||||
} |
||||
|
||||
static void test_date_time_epoch(void) |
||||
{ |
||||
/*
|
||||
CBOR: unsigned integer marked with a tag 1 to indicate it is a |
||||
standard date/time epoch (similar to time_t) |
||||
*/ |
||||
unsigned char data[] = {0xC1, 0x01}; |
||||
time_t val = 1; |
||||
TEST_ASSERT(cbor_serialize_date_time_epoch(&stream, val)); |
||||
CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); |
||||
time_t val2 = 0; |
||||
TEST_ASSERT(cbor_deserialize_date_time_epoch(&stream, 0, &val2)); |
||||
CBOR_CHECK_DESERIALIZED(val, val2, EQUAL_INT); |
||||
} |
||||
#endif /* CBOR_NO_CTIME */ |
||||
#endif /* CBOR_NO_SEMANTIC_TAGGING */ |
||||
|
||||
static void test_bool(void) |
||||
{ |
||||
CBOR_CHECK(bool, bool, stream, false, HEX_LITERAL(0xf4), EQUAL_INT); |
||||
CBOR_CHECK(bool, bool, stream, true, HEX_LITERAL(0xf5), EQUAL_INT); |
||||
} |
||||
|
||||
static void test_bool_invalid(void) |
||||
{ |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_bool(&empty_stream, true)); |
||||
TEST_ASSERT_EQUAL_INT(0, empty_stream.pos); |
||||
|
||||
bool val_bool = 0; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_bool(&invalid_stream, 0, &val_bool)); |
||||
} |
||||
|
||||
#ifndef CBOR_NO_FLOAT |
||||
static void test_float_half(void) |
||||
{ |
||||
/* check border conditions */ |
||||
CBOR_CHECK(float, float_half, stream, -.0f, HEX_LITERAL(0xf9, 0x80, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float_half, stream, .0f, HEX_LITERAL(0xf9, 0x00, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float_half, stream, INFINITY, HEX_LITERAL(0xf9, 0x7c, 0x00), EQUAL_FLOAT); |
||||
/* TODO: Broken: encode_float_half issue? */ |
||||
/*CBOR_CHECK(float, float_half, stream, NAN, HEX_LITERAL(0xf9, 0x7e, 0x00), EQUAL_FLOAT);*/ |
||||
CBOR_CHECK(float, float_half, stream, -INFINITY, HEX_LITERAL(0xf9, 0xfc, 0x00), EQUAL_FLOAT); |
||||
|
||||
/* check examples from the CBOR RFC */ |
||||
CBOR_CHECK(float, float_half, stream, -4.f, HEX_LITERAL(0xf9, 0xc4, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float_half, stream, 1.f, HEX_LITERAL(0xf9, 0x3c, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float_half, stream, 1.5f, HEX_LITERAL(0xf9, 0x3e, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float_half, stream, 5.960464477539063e-8, |
||||
HEX_LITERAL(0xf9, 0x00, 0x01), EQUAL_FLOAT); |
||||
} |
||||
|
||||
static void test_float_half_invalid(void) |
||||
{ |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_float_half(&empty_stream, 0.f)); |
||||
TEST_ASSERT_EQUAL_INT(0, empty_stream.pos); |
||||
|
||||
float val_float_half = 0; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_float_half(&invalid_stream, 0, &val_float_half)); |
||||
} |
||||
|
||||
|
||||
static void test_float(void) |
||||
|
||||
{ |
||||
/* check border conditions */ |
||||
CBOR_CHECK(float, float, stream, .0f, |
||||
HEX_LITERAL(0xfa, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float, stream, INFINITY, |
||||
HEX_LITERAL(0xfa, 0x7f, 0x80, 0x00, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float, stream, NAN, |
||||
HEX_LITERAL(0xfa, 0x7f, 0xc0, 0x00, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float, stream, -INFINITY, |
||||
HEX_LITERAL(0xfa, 0xff, 0x80, 0x00, 0x00), EQUAL_FLOAT); |
||||
|
||||
/* check examples from the CBOR RFC */ |
||||
CBOR_CHECK(float, float, stream, 100000.f, |
||||
HEX_LITERAL(0xfa, 0x47, 0xc3, 0x50, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(float, float, stream, 3.4028234663852886e+38, |
||||
HEX_LITERAL(0xfa, 0x7f, 0x7f, 0xff, 0xff), EQUAL_FLOAT); |
||||
} |
||||
|
||||
static void test_float_invalid(void) |
||||
{ |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_float(&empty_stream, 0.f)); |
||||
TEST_ASSERT_EQUAL_INT(0, empty_stream.pos); |
||||
|
||||
float val_float = 0; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_float(&invalid_stream, 0, &val_float)); |
||||
} |
||||
|
||||
static void test_double(void) |
||||
{ |
||||
/* check border conditions */ |
||||
CBOR_CHECK(double, double, stream, .0f, |
||||
HEX_LITERAL(0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(double, double, stream, INFINITY, |
||||
HEX_LITERAL(0xfb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(double, double, stream, NAN, |
||||
HEX_LITERAL(0xfb, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT); |
||||
CBOR_CHECK(double, double, stream, -INFINITY, |
||||
HEX_LITERAL(0xfb, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT); |
||||
|
||||
/* check examples from the CBOR RFC */ |
||||
CBOR_CHECK(double, double, stream, 1.1, |
||||
HEX_LITERAL(0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a), EQUAL_FLOAT); |
||||
CBOR_CHECK(double, double, stream, -4.1, |
||||
HEX_LITERAL(0xfb, 0xc0, 0x10, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66), EQUAL_FLOAT); |
||||
#if ARCH_32_BIT |
||||
CBOR_CHECK(double, double, stream, 1.e+300, |
||||
HEX_LITERAL(0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c), EQUAL_FLOAT); |
||||
#endif |
||||
} |
||||
|
||||
static void test_double_invalid(void) |
||||
{ |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_serialize_double(&empty_stream, 0)); |
||||
TEST_ASSERT_EQUAL_INT(0, empty_stream.pos); |
||||
|
||||
|
||||
double val_double = 0; |
||||
TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_double(&invalid_stream, 0, &val_double)); |
||||
} |
||||
#endif /* CBOR_NO_FLOAT */ |
||||
|
||||
#ifndef CBOR_NO_PRINT |
||||
/**
|
||||
* Manual test for testing the cbor_stream_decode function |
||||
*/ |
||||
void test_stream_decode(void) |
||||
{ |
||||
cbor_clear(&stream); |
||||
|
||||
cbor_serialize_int(&stream, 1); |
||||
cbor_serialize_uint64_t(&stream, 2llu); |
||||
cbor_serialize_int64_t(&stream, 3); |
||||
cbor_serialize_int64_t(&stream, -5); |
||||
cbor_serialize_bool(&stream, true); |
||||
#ifndef CBOR_NO_FLOAT |
||||
cbor_serialize_float_half(&stream, 1.1f); |
||||
cbor_serialize_float(&stream, 1.5f); |
||||
cbor_serialize_double(&stream, 2.0); |
||||
#endif /* CBOR_NO_FLOAT */ |
||||
cbor_serialize_byte_string(&stream, "abc"); |
||||
cbor_serialize_unicode_string(&stream, "def"); |
||||
|
||||
cbor_serialize_array(&stream, 2); |
||||
cbor_serialize_int(&stream, 0); |
||||
cbor_serialize_int(&stream, 1); |
||||
|
||||
cbor_serialize_array_indefinite(&stream); |
||||
cbor_serialize_int(&stream, 10); |
||||
cbor_serialize_int(&stream, 11); |
||||
cbor_write_break(&stream); |
||||
|
||||
cbor_serialize_map(&stream, 2); |
||||
cbor_serialize_int(&stream, 1); |
||||
cbor_serialize_byte_string(&stream, "1"); |
||||
cbor_serialize_int(&stream, 2); |
||||
cbor_serialize_byte_string(&stream, "2"); |
||||
|
||||
cbor_serialize_map_indefinite(&stream); |
||||
cbor_serialize_int(&stream, 10); |
||||
cbor_serialize_byte_string(&stream, "10"); |
||||
cbor_serialize_int(&stream, 11); |
||||
cbor_serialize_byte_string(&stream, "11"); |
||||
cbor_write_break(&stream); |
||||
|
||||
#ifndef CBOR_NO_SEMANTIC_TAGGING |
||||
#ifndef CBOR_NO_CTIME |
||||
time_t rawtime; |
||||
time(&rawtime); |
||||
struct tm *timeinfo = localtime(&rawtime); |
||||
cbor_serialize_date_time(&stream, timeinfo); |
||||
cbor_serialize_date_time_epoch(&stream, rawtime); |
||||
#endif /* CBOR_NO_CTIME */ |
||||
|
||||
// decoder should skip the tag and print 'unsupported' here
|
||||
cbor_write_tag(&stream, 2); |
||||
cbor_serialize_byte_string(&stream, "1"); |
||||
#endif /* CBOR_NO_SEMANTIC_TAGGING */ |
||||
|
||||
cbor_stream_decode(&stream); |
||||
} |
||||
#endif /* CBOR_NO_PRINT */ |
||||
|
||||
/**
|
||||
* See examples from CBOR RFC (cf. Appendix A. Examples) |
||||
*/ |
||||
TestRef tests_cbor_all(void) |
||||
{ |
||||
EMB_UNIT_TESTFIXTURES(fixtures) { |
||||
new_TestFixture(test_int), |
||||
new_TestFixture(test_int_invalid), |
||||
new_TestFixture(test_uint64_t), |
||||
new_TestFixture(test_uint64_t_invalid), |
||||
new_TestFixture(test_int64_t), |
||||
new_TestFixture(test_int64_t_invalid), |
||||
new_TestFixture(test_byte_string), |
||||
new_TestFixture(test_byte_string_invalid), |
||||
new_TestFixture(test_unicode_string), |
||||
new_TestFixture(test_unicode_string_invalid), |
||||
new_TestFixture(test_array), |
||||
new_TestFixture(test_array_indefinite), |
||||
new_TestFixture(test_array_invalid), |
||||
new_TestFixture(test_map), |
||||
new_TestFixture(test_map_indefinite), |
||||
new_TestFixture(test_map_invalid), |
||||
#ifndef CBOR_NO_SEMANTIC_TAGGING |
||||
new_TestFixture(test_semantic_tagging), |
||||
#ifndef CBOR_NO_CTIME |
||||
new_TestFixture(test_date_time), |
||||
new_TestFixture(test_date_time_epoch), |
||||
#endif /* CBOR_NO_CTIME */ |
||||
#endif /* CBOR_NO_SEMANTIC_TAGGING */ |
||||
new_TestFixture(test_bool), |
||||
new_TestFixture(test_bool_invalid), |
||||
#ifndef CBOR_NO_FLOAT |
||||
new_TestFixture(test_float_half), |
||||
new_TestFixture(test_float_half_invalid), |
||||
new_TestFixture(test_float), |
||||
new_TestFixture(test_float_invalid), |
||||
new_TestFixture(test_double), |
||||
new_TestFixture(test_double_invalid), |
||||
#endif /* CBOR_NO_FLOAT */ |
||||
}; |
||||
|
||||
EMB_UNIT_TESTCALLER(CborTest, setUp, tearDown, fixtures); |
||||
return (TestRef)&CborTest; |
||||
} |
||||
|
||||
void tests_cbor(void) |
||||
{ |
||||
#ifndef CBOR_NO_PRINT |
||||
test_stream_decode(); |
||||
#endif /* CBOR_NO_PRINT */ |
||||
|
||||
TESTS_RUN(tests_cbor_all()); |
||||
} |
Loading…
Reference in new issue