diff options
-rw-r--r-- | pb.h | 9 | ||||
-rw-r--r-- | pb_decode.c | 7 | ||||
-rw-r--r-- | tests/Makefile | 12 | ||||
-rw-r--r-- | tests/decode_unittests.c | 111 | ||||
-rw-r--r-- | tests/test_decode1.c | 30 |
5 files changed, 145 insertions, 24 deletions
@@ -112,8 +112,6 @@ struct _pb_field_t { const void *ptr; } pb_packed; -#define PB_LAST_FIELD {0,0,0,0} - /* This structure is used for 'bytes' arrays. * It has the number of bytes in the beginning, and after that an array. */ #define PB_BYTES_ARRAY(buffersize) \ @@ -152,4 +150,11 @@ struct _pb_callback_t { void *arg; }; +/* These macros are used to declare pb_field_t's in the constant array. */ +#define pb_membersize(st, m) (sizeof ((st*)0)->m) +#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) +#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) +#define PB_LAST_FIELD {0,0,0,0} + + #endif
\ No newline at end of file diff --git a/pb_decode.c b/pb_decode.c index 58d64805..63008dd5 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -23,13 +23,14 @@ const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count) { - bool status; if (stream->bytes_left < count) return false; - status = stream->callback(stream, buf, count); + if (!stream->callback(stream, buf, count)) + return false; + stream->bytes_left -= count; - return status; + return true; } static bool buf_read(pb_istream_t *stream, uint8_t *buf, size_t count) diff --git a/tests/Makefile b/tests/Makefile index d357c674..ddf91ebb 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,13 +1,17 @@ -CFLAGS=-ansi -pedantic -Wall -I .. -g -O0 +CFLAGS=-ansi -Wall -Werror -I .. -g -O0 DEPS=../pb_decode.c ../pb_decode.h ../pb.h +TESTS=test_decode1 decode_unittests -all: test_decode1 +all: $(TESTS) clean: rm -f test_decode1 -test_decode1: test_decode1.c $(DEPS) +%: %.c $(DEPS) $(CC) $(CFLAGS) -o $@ $< ../pb_decode.c -fuzztest: test_decode1 +run_unittests: decode_unittests + ./decode_unittests + +run_fuzztest: test_decode1 bash -c 'I=1; while cat /dev/urandom | ./test_decode1 > /dev/null; do I=$$(($$I+1)); echo -en "\r$$I"; done'
\ No newline at end of file diff --git a/tests/decode_unittests.c b/tests/decode_unittests.c new file mode 100644 index 00000000..746b7e96 --- /dev/null +++ b/tests/decode_unittests.c @@ -0,0 +1,111 @@ +#include <stdio.h> +#include <string.h> +#include "pb_decode.h" + +#define COMMENT(x) printf("\n----" x "----\n"); +#define STR(x) #x +#define STR2(x) STR(x) +#define TEST(x) \ + if (!(x)) { \ + fprintf(stderr, __FILE__ ":" STR2(__LINE__) " FAILED:" #x "\n"); \ + status = 1; \ + } else { \ + printf("OK: " #x "\n"); \ + } + +#define S(x) pb_istream_from_buffer((uint8_t*)x, sizeof(x)) + +bool stream_callback(pb_istream_t *stream, uint8_t *buf, size_t count) +{ + if (stream->state != NULL) + return false; /* Simulate error */ + + if (buf != NULL) + memset(buf, 'x', count); + return true; +} + +int main() +{ + int status = 0; + + { + uint8_t buffer1[] = "foobartest1234"; + uint8_t buffer2[sizeof(buffer1)]; + pb_istream_t stream = pb_istream_from_buffer(buffer1, sizeof(buffer1)); + + COMMENT("Test pb_read and pb_istream_t"); + TEST(pb_read(&stream, buffer2, 6)) + TEST(memcmp(buffer2, "foobar", 6) == 0) + TEST(stream.bytes_left == sizeof(buffer1) - 6) + TEST(pb_read(&stream, buffer2 + 6, stream.bytes_left)) + TEST(memcmp(buffer1, buffer2, sizeof(buffer1)) == 0) + TEST(stream.bytes_left == 0) + TEST(!pb_read(&stream, buffer2, 1)) + } + + { + uint8_t buffer[20]; + pb_istream_t stream = {&stream_callback, NULL, 20}; + + COMMENT("Test pb_read with custom callback"); + TEST(pb_read(&stream, buffer, 5)) + TEST(memcmp(buffer, "xxxxx", 5) == 0) + TEST(!pb_read(&stream, buffer, 50)) + stream.state = (void*)1; /* Simulated error return from callback */ + TEST(!pb_read(&stream, buffer, 5)) + stream.state = NULL; + TEST(pb_read(&stream, buffer, 15)) + } + + { + pb_istream_t s; + uint32_t u; + int32_t i; + + COMMENT("Test pb_decode_varint32"); + TEST((s = S("\x00"), pb_decode_varint32(&s, &u) && u == 0)); + TEST((s = S("\x01"), pb_decode_varint32(&s, &u) && u == 1)); + TEST((s = S("\xAC\x02"), pb_decode_varint32(&s, &u) && u == 300)); + TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint32(&s, &u) && u == UINT32_MAX)); + TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint32(&s, (uint32_t*)&i) && i == -1)); + } + + { + pb_istream_t s; + uint64_t u; + int64_t i; + + COMMENT("Test pb_decode_varint64"); + TEST((s = S("\x00"), pb_decode_varint64(&s, &u) && u == 0)); + TEST((s = S("\x01"), pb_decode_varint64(&s, &u) && u == 1)); + TEST((s = S("\xAC\x02"), pb_decode_varint64(&s, &u) && u == 300)); + TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint64(&s, &u) && u == UINT32_MAX)); + TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint64(&s, (uint64_t*)&i) && i == UINT32_MAX)); + TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), + pb_decode_varint64(&s, (uint64_t*)&i) && i == -1)); + TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), + pb_decode_varint64(&s, &u) && u == UINT64_MAX)); + } + + { + pb_istream_t s; + COMMENT("Test pb_skip_varint"); + TEST((s = S("\x00""foobar"), pb_skip_varint(&s) && s.bytes_left == 7)) + TEST((s = S("\xAC\x02""foobar"), pb_skip_varint(&s) && s.bytes_left == 7)) + TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01""foobar"), + pb_skip_varint(&s) && s.bytes_left == 7)) + } + + { + pb_istream_t s; + COMMENT("Test pb_skip_string") + TEST((s = S("\x00""foobar"), pb_skip_string(&s) && s.bytes_left == 7)) + TEST((s = S("\x04""testfoobar"), pb_skip_string(&s) && s.bytes_left == 7)) + } + + if (status != 0) + fprintf(stdout, "\n\nSome tests FAILED!\n"); + + return status; +} diff --git a/tests/test_decode1.c b/tests/test_decode1.c index a507b0dc..4b34022f 100644 --- a/tests/test_decode1.c +++ b/tests/test_decode1.c @@ -27,20 +27,20 @@ typedef struct { } Person; /* Field descriptions */ -#define membersize(st, m) (sizeof ((st*)0)->m) -const Person_PhoneType Person_PhoneType_type_default = Person_PhoneType_HOME; + +const Person_PhoneType Person_PhoneNumber_type_default = Person_PhoneType_HOME; const pb_field_t Person_PhoneNumber_fields[] = { {1, PB_HTYPE_REQUIRED | PB_LTYPE_STRING, offsetof(Person_PhoneNumber, number), 0, - membersize(Person_PhoneNumber, number), 0, 0}, + pb_membersize(Person_PhoneNumber, number), 0, 0}, {2, PB_HTYPE_OPTIONAL | PB_LTYPE_VARINT, - offsetof(Person_PhoneNumber, type) - offsetof(Person_PhoneNumber, number), - (int)offsetof(Person_PhoneNumber, has_type) - (int)offsetof(Person_PhoneNumber, type), - membersize(Person_PhoneNumber, type), 0, - &Person_PhoneType_type_default}, + pb_delta(Person_PhoneNumber, type, number), + pb_delta(Person_PhoneNumber, has_type, type), + pb_membersize(Person_PhoneNumber, type), 0, + &Person_PhoneNumber_type_default}, PB_LAST_FIELD }; @@ -48,22 +48,22 @@ const pb_field_t Person_PhoneNumber_fields[] = { const pb_field_t Person_fields[] = { {1, PB_HTYPE_REQUIRED | PB_LTYPE_STRING, offsetof(Person, name), 0, - membersize(Person, name), 0, 0}, + pb_membersize(Person, name), 0, 0}, {2, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT, - offsetof(Person, id) - offsetof(Person, name), 0, - membersize(Person, id), 0, 0}, + pb_delta(Person, id, name), 0, + pb_membersize(Person, id), 0, 0}, {3, PB_HTYPE_OPTIONAL | PB_LTYPE_STRING, offsetof(Person, email) - offsetof(Person, id), - (int)offsetof(Person, has_email) - (int)offsetof(Person, email), - membersize(Person, email), 0, 0}, + pb_delta(Person, has_email, email), + pb_membersize(Person, email), 0, 0}, {4, PB_HTYPE_ARRAY | PB_LTYPE_SUBMESSAGE, offsetof(Person, phone) - offsetof(Person, email), - (int)offsetof(Person, phone_size) - (int)offsetof(Person, phone), - membersize(Person, phone[0]), - membersize(Person, phone) / membersize(Person, phone[0]), + pb_delta(Person, phone_size, phone), + pb_membersize(Person, phone[0]), + pb_arraysize(Person, phone), Person_PhoneNumber_fields}, PB_LAST_FIELD |