summaryrefslogtreecommitdiff
path: root/tests/test_decoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_decoder.c')
-rw-r--r--tests/test_decoder.c668
1 files changed, 0 insertions, 668 deletions
diff --git a/tests/test_decoder.c b/tests/test_decoder.c
deleted file mode 100644
index 14d0e2d..0000000
--- a/tests/test_decoder.c
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2011 Google Inc. See LICENSE for details.
- *
- * An exhaustive set of tests for parsing both valid and invalid protobuf
- * input, with buffer breaks in arbitrary places.
- *
- * Tests to add:
- * - unknown field handler called appropriately
- * - unknown fields can be inserted in random places
- * - fuzzing of valid input
- * - resource limits (max stack depth, max string len)
- * - testing of groups
- * - more throrough testing of sequences
- * - test skipping of submessages
- * - test suspending the decoder
- * - buffers that are close enough to the end of the address space that
- * pointers overflow (this might be difficult).
- * - a few "kitchen sink" examples (one proto that uses all types, lots
- * of submsg/sequences, etc.
- */
-
-#include <inttypes.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include "upb/handlers.h"
-#include "upb/pb/decoder.h"
-#include "upb/pb/varint.h"
-#include "upb/upb.h"
-#include "upb_test.h"
-
-typedef struct {
- char *buf;
- size_t len;
-} buffer;
-
-// Mem is initialized to NULL.
-buffer *buffer_new(size_t len) {
- buffer *buf = malloc(sizeof(*buf));
- buf->buf = malloc(len);
- buf->len = len;
- memset(buf->buf, 0, buf->len);
- return buf;
-}
-
-buffer *buffer_new2(const void *data, size_t len) {
- buffer *buf = buffer_new(len);
- memcpy(buf->buf, data, len);
- return buf;
-}
-
-buffer *buffer_new3(const char *data) {
- return buffer_new2(data, strlen(data));
-}
-
-buffer *buffer_dup(buffer *buf) { return buffer_new2(buf->buf, buf->len); }
-
-void buffer_free(buffer *buf) {
- free(buf->buf);
- free(buf);
-}
-
-void buffer_appendf(buffer *buf, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- size_t size = buf->len;
- buf->len += upb_vrprintf(&buf->buf, &size, buf->len, fmt, args);
- va_end(args);
-}
-
-void buffer_cat(buffer *buf, buffer *buf2) {
- size_t newlen = buf->len + buf2->len;
- buf->buf = realloc(buf->buf, newlen);
- memcpy(buf->buf + buf->len, buf2->buf, buf2->len);
- buf->len = newlen;
- buffer_free(buf2);
-}
-
-bool buffer_eql(buffer *buf, buffer *buf2) {
- return buf->len == buf2->len && memcmp(buf->buf, buf2->buf, buf->len) == 0;
-}
-
-
-/* Routines for building arbitrary protos *************************************/
-
-buffer *cat(buffer *arg1, ...) {
- va_list ap;
- buffer *arg;
- va_start(ap, arg1);
- while ((arg = va_arg(ap, buffer*)) != NULL) {
- buffer_cat(arg1, arg);
- }
- va_end(ap);
- return arg1;
-}
-
-buffer *varint(uint64_t x) {
- buffer *buf = buffer_new(UPB_PB_VARINT_MAX_LEN + 1);
- buf->len = upb_vencode64(x, buf->buf);
- return buf;
-}
-
-// TODO: proper byte-swapping for big-endian machines.
-buffer *fixed32(void *data) { return buffer_new2(data, 4); }
-buffer *fixed64(void *data) { return buffer_new2(data, 8); }
-
-buffer *delim(buffer *buf) { return cat( varint(buf->len), buf, NULL ); }
-buffer *uint32(uint32_t u32) { return fixed32(&u32); }
-buffer *uint64(uint64_t u64) { return fixed64(&u64); }
-buffer *flt(float f) { return fixed32(&f); }
-buffer *dbl(double d) { return fixed64(&d); }
-buffer *zz32(int32_t x) { return varint(upb_zzenc_32(x)); }
-buffer *zz64(int64_t x) { return varint(upb_zzenc_64(x)); }
-
-buffer *tag(uint32_t fieldnum, char wire_type) {
- return varint((fieldnum << 3) | wire_type);
-}
-
-buffer *submsg(uint32_t fn, buffer *buf) {
- return cat( tag(fn, UPB_WIRE_TYPE_DELIMITED), delim(buf), NULL );
-}
-
-
-/* A set of handlers that covers all .proto types *****************************/
-
-// The handlers simply append to a string indicating what handlers were called.
-// This string is similar to protobuf text format but fields are referred to by
-// number instead of name and sequences are explicitly delimited.
-
-#define VALUE_HANDLER(member, fmt) \
- upb_flow_t value_ ## member(void *closure, upb_value fval, upb_value val) { \
- buffer_appendf(closure, "%" PRIu32 ":%" fmt "; ", \
- upb_value_getuint32(fval), upb_value_get ## member(val)); \
- return UPB_CONTINUE; \
- }
-
-VALUE_HANDLER(uint32, PRIu32)
-VALUE_HANDLER(uint64, PRIu64)
-VALUE_HANDLER(int32, PRId32)
-VALUE_HANDLER(int64, PRId64)
-VALUE_HANDLER(float, "g")
-VALUE_HANDLER(double, "g")
-
-upb_flow_t value_bool(void *closure, upb_value fval, upb_value val) {
- buffer_appendf(closure, "%" PRIu32 ":%s; ",
- upb_value_getuint32(fval),
- upb_value_getbool(val) ? "true" : "false");
- return UPB_CONTINUE;
-}
-
-upb_flow_t value_string(void *closure, upb_value fval, upb_value val) {
- // Note: won't work with strings that contain NULL.
- char *str = upb_byteregion_strdup(upb_value_getbyteregion(val));
- buffer_appendf(closure, "%" PRIu32 ":%s; ", upb_value_getuint32(fval), str);
- free(str);
- return UPB_CONTINUE;
-}
-
-upb_sflow_t startsubmsg(void *closure, upb_value fval) {
- buffer_appendf(closure, "%" PRIu32 ":{ ", upb_value_getuint32(fval));
- return UPB_CONTINUE_WITH(closure);
-}
-
-upb_flow_t endsubmsg(void *closure, upb_value fval) {
- (void)fval;
- buffer_appendf(closure, "} ");
- return UPB_CONTINUE;
-}
-
-upb_sflow_t startseq(void *closure, upb_value fval) {
- buffer_appendf(closure, "%" PRIu32 ":[ ", upb_value_getuint32(fval));
- return UPB_CONTINUE_WITH(closure);
-}
-
-upb_flow_t endseq(void *closure, upb_value fval) {
- (void)fval;
- buffer_appendf(closure, "] ");
- return UPB_CONTINUE;
-}
-
-void doreg(upb_mhandlers *m, uint32_t num, upb_fieldtype_t type, bool repeated,
- upb_value_handler *handler) {
- upb_fhandlers *f = upb_mhandlers_newfhandlers(m, num, type, repeated);
- ASSERT(f);
- upb_fhandlers_setvalue(f, handler);
- upb_fhandlers_setstartseq(f, &startseq);
- upb_fhandlers_setendseq(f, &endseq);
- upb_fhandlers_setfval(f, upb_value_uint32(num));
-}
-
-// The repeated field number to correspond to the given non-repeated field
-// number.
-uint32_t rep_fn(uint32_t fn) {
- return (UPB_MAX_FIELDNUMBER - 1000) + fn;
-}
-
-#define NOP_FIELD 40
-#define UNKNOWN_FIELD 666
-
-void reg(upb_mhandlers *m, upb_fieldtype_t type, upb_value_handler *handler) {
- // We register both a repeated and a non-repeated field for every type.
- // For the non-repeated field we make the field number the same as the
- // type. For the repeated field we make it a function of the type.
- doreg(m, type, type, false, handler);
- doreg(m, rep_fn(type), type, true, handler);
-}
-
-void reg_subm(upb_mhandlers *m, uint32_t num, upb_fieldtype_t type,
- bool repeated) {
- upb_fhandlers *f =
- upb_mhandlers_newfhandlers_subm(m, num, type, repeated, m);
- ASSERT(f);
- upb_fhandlers_setstartseq(f, &startseq);
- upb_fhandlers_setendseq(f, &endseq);
- upb_fhandlers_setstartsubmsg(f, &startsubmsg);
- upb_fhandlers_setendsubmsg(f, &endsubmsg);
- upb_fhandlers_setfval(f, upb_value_uint32(num));
-}
-
-void reghandlers(upb_mhandlers *m) {
- // Register handlers for each type.
- reg(m, UPB_TYPE(DOUBLE), &value_double);
- reg(m, UPB_TYPE(FLOAT), &value_float);
- reg(m, UPB_TYPE(INT64), &value_int64);
- reg(m, UPB_TYPE(UINT64), &value_uint64);
- reg(m, UPB_TYPE(INT32) , &value_int32);
- reg(m, UPB_TYPE(FIXED64), &value_uint64);
- reg(m, UPB_TYPE(FIXED32), &value_uint32);
- reg(m, UPB_TYPE(BOOL), &value_bool);
- reg(m, UPB_TYPE(STRING), &value_string);
- reg(m, UPB_TYPE(BYTES), &value_string);
- reg(m, UPB_TYPE(UINT32), &value_uint32);
- reg(m, UPB_TYPE(ENUM), &value_int32);
- reg(m, UPB_TYPE(SFIXED32), &value_int32);
- reg(m, UPB_TYPE(SFIXED64), &value_int64);
- reg(m, UPB_TYPE(SINT32), &value_int32);
- reg(m, UPB_TYPE(SINT64), &value_int64);
-
- // Register submessage/group handlers that are self-recursive
- // to this type, eg: message M { optional M m = 1; }
- reg_subm(m, UPB_TYPE(MESSAGE), UPB_TYPE(MESSAGE), false);
- reg_subm(m, UPB_TYPE(GROUP), UPB_TYPE(GROUP), false);
- reg_subm(m, rep_fn(UPB_TYPE(MESSAGE)), UPB_TYPE(MESSAGE), true);
- reg_subm(m, rep_fn(UPB_TYPE(GROUP)), UPB_TYPE(GROUP), true);
-
- // Register a no-op string field so we can pad the proto wherever we want.
- upb_mhandlers_newfhandlers(m, NOP_FIELD, UPB_TYPE(STRING), false);
-}
-
-
-/* Custom bytesrc that can insert buffer seams in arbitrary places ************/
-
-typedef struct {
- upb_bytesrc bytesrc;
- const char *str;
- size_t len, seam1, seam2;
- upb_byteregion byteregion;
-} upb_seamsrc;
-
-size_t upb_seamsrc_avail(const upb_seamsrc *src, size_t ofs) {
- if (ofs < src->seam1) return src->seam1 - ofs;
- if (ofs < src->seam2) return src->seam2 - ofs;
- return src->len - ofs;
-}
-
-upb_bytesuccess_t upb_seamsrc_fetch(void *_src, uint64_t ofs, size_t *read) {
- upb_seamsrc *src = _src;
- assert(ofs < src->len);
- if (ofs == src->len) {
- upb_status_seteof(&src->bytesrc.status);
- return UPB_BYTE_EOF;
- }
- *read = upb_seamsrc_avail(src, ofs);
- return UPB_BYTE_OK;
-}
-
-void upb_seamsrc_copy(const void *_src, uint64_t ofs,
- size_t len, char *dst) {
- const upb_seamsrc *src = _src;
- assert(ofs + len <= src->len);
- memcpy(dst, src->str + ofs, len);
-}
-
-void upb_seamsrc_discard(void *src, uint64_t ofs) {
- (void)src;
- (void)ofs;
-}
-
-const char *upb_seamsrc_getptr(const void *_s, uint64_t ofs, size_t *len) {
- const upb_seamsrc *src = _s;
- *len = upb_seamsrc_avail(src, ofs);
- return src->str + ofs;
-}
-
-void upb_seamsrc_init(upb_seamsrc *s, const char *str, size_t len) {
- static upb_bytesrc_vtbl vtbl = {
- &upb_seamsrc_fetch,
- &upb_seamsrc_discard,
- &upb_seamsrc_copy,
- &upb_seamsrc_getptr,
- };
- upb_bytesrc_init(&s->bytesrc, &vtbl);
- s->seam1 = 0;
- s->seam2 = 0;
- s->str = str;
- s->len = len;
- s->byteregion.bytesrc = &s->bytesrc;
- s->byteregion.toplevel = true;
- s->byteregion.start = 0;
- s->byteregion.end = len;
-}
-
-void upb_seamsrc_resetseams(upb_seamsrc *s, size_t seam1, size_t seam2) {
- ASSERT(seam1 <= seam2);
- s->seam1 = seam1;
- s->seam2 = seam2;
- s->byteregion.discard = 0;
- s->byteregion.fetch = 0;
-}
-
-void upb_seamsrc_uninit(upb_seamsrc *s) { (void)s; }
-
-upb_bytesrc *upb_seamsrc_bytesrc(upb_seamsrc *s) {
- return &s->bytesrc;
-}
-
-// Returns the top-level upb_byteregion* for this seamsrc. Invalidated when
-// the seamsrc is reset.
-upb_byteregion *upb_seamsrc_allbytes(upb_seamsrc *s) {
- return &s->byteregion;
-}
-
-
-/* Running of test cases ******************************************************/
-
-upb_decoderplan *plan;
-
-void run_decoder(buffer *proto, buffer *expected_output) {
- upb_seamsrc src;
- upb_seamsrc_init(&src, proto->buf, proto->len);
- upb_decoder d;
- upb_decoder_init(&d);
- upb_decoder_resetplan(&d, plan, 0);
- for (size_t i = 0; i < proto->len; i++) {
- for (size_t j = i; j < proto->len; j++) {
- upb_seamsrc_resetseams(&src, i, j);
- upb_byteregion *input = upb_seamsrc_allbytes(&src);
- buffer *output = buffer_new(0);
- upb_decoder_resetinput(&d, input, output);
- upb_success_t success = UPB_SUSPENDED;
- while (success == UPB_SUSPENDED)
- success = upb_decoder_decode(&d);
- ASSERT(upb_ok(upb_decoder_status(&d)) == (success == UPB_OK));
- if (expected_output) {
- ASSERT(success == UPB_OK);
- // The input should be fully consumed.
- ASSERT(upb_byteregion_fetchofs(input) == upb_byteregion_endofs(input));
- ASSERT(upb_byteregion_discardofs(input) ==
- upb_byteregion_endofs(input));
- if (!buffer_eql(output, expected_output)) {
- fprintf(stderr, "Text mismatch: '%s' vs '%s'\n",
- output->buf, expected_output->buf);
- }
- ASSERT(strcmp(output->buf, expected_output->buf) == 0);
- } else {
- ASSERT(success == UPB_ERROR);
- }
- buffer_free(output);
- }
- }
- upb_seamsrc_uninit(&src);
- upb_decoder_uninit(&d);
- buffer_free(proto);
-}
-
-void assert_successful_parse_at_eof(buffer *proto, const char *expected_fmt,
- va_list args) {
- buffer *expected_text = buffer_new(0);
- size_t size = expected_text->len;
- expected_text->len += upb_vrprintf(&expected_text->buf, &size,
- expected_text->len, expected_fmt, args);
- run_decoder(proto, expected_text);
- buffer_free(expected_text);
-}
-
-void assert_does_not_parse_at_eof(buffer *proto) {
- run_decoder(proto, NULL);
-}
-
-void assert_successful_parse(buffer *proto, const char *expected_fmt, ...) {
- // The JIT is only used for data >=20 bytes from end-of-buffer, so
- // repeat once with no-op padding data at the end of buffer.
- va_list args, args2;
- va_start(args, expected_fmt);
- va_copy(args2, args);
- assert_successful_parse_at_eof(buffer_dup(proto), expected_fmt, args);
- assert_successful_parse_at_eof(
- cat( proto,
- tag(NOP_FIELD, UPB_WIRE_TYPE_DELIMITED), delim(buffer_new(30)),
- NULL ),
- expected_fmt, args2);
- va_end(args);
- va_end(args2);
-}
-
-void assert_does_not_parse(buffer *proto) {
- // The JIT is only used for data >=20 bytes from end-of-buffer, so
- // repeat once with no-op padding data at the end of buffer.
- assert_does_not_parse_at_eof(buffer_dup(proto));
- assert_does_not_parse_at_eof(
- cat( proto,
- tag(NOP_FIELD, UPB_WIRE_TYPE_DELIMITED), delim( buffer_new(30)),
- NULL ));
-}
-
-
-/* The actual tests ***********************************************************/
-
-void test_premature_eof_for_type(upb_fieldtype_t type) {
- // Incomplete values for each wire type.
- static const char *incompletes[] = {
- "\x80", // UPB_WIRE_TYPE_VARINT
- "abcdefg", // UPB_WIRE_TYPE_64BIT
- "\x80", // UPB_WIRE_TYPE_DELIMITED (partial length)
- NULL, // UPB_WIRE_TYPE_START_GROUP (no value required)
- NULL, // UPB_WIRE_TYPE_END_GROUP (no value required)
- "abc" // UPB_WIRE_TYPE_32BIT
- };
-
- uint32_t fieldnum = type;
- uint32_t rep_fieldnum = rep_fn(type);
- int wire_type = upb_types[type].native_wire_type;
- const char *incomplete = incompletes[wire_type];
-
- // EOF before a known non-repeated value.
- assert_does_not_parse_at_eof(tag(fieldnum, wire_type));
-
- // EOF before a known repeated value.
- assert_does_not_parse_at_eof(tag(rep_fieldnum, wire_type));
-
- // EOF before an unknown value.
- assert_does_not_parse_at_eof(tag(UNKNOWN_FIELD, wire_type));
-
- // EOF inside a known non-repeated value.
- assert_does_not_parse_at_eof(
- cat( tag(fieldnum, wire_type), buffer_new3(incomplete), NULL ));
-
- // EOF inside a known repeated value.
- assert_does_not_parse_at_eof(
- cat( tag(rep_fieldnum, wire_type), buffer_new3(incomplete), NULL ));
-
- // EOF inside an unknown value.
- assert_does_not_parse_at_eof(
- cat( tag(UNKNOWN_FIELD, wire_type), buffer_new3(incomplete), NULL ));
-
- if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
- // EOF in the middle of delimited data for known non-repeated value.
- assert_does_not_parse_at_eof(
- cat( tag(fieldnum, wire_type), varint(1), NULL ));
-
- // EOF in the middle of delimited data for known repeated value.
- assert_does_not_parse_at_eof(
- cat( tag(rep_fieldnum, wire_type), varint(1), NULL ));
-
- // EOF in the middle of delimited data for unknown value.
- assert_does_not_parse_at_eof(
- cat( tag(UNKNOWN_FIELD, wire_type), varint(1), NULL ));
-
- if (type == UPB_TYPE(MESSAGE)) {
- // Submessage ends in the middle of a value.
- buffer *incomplete_submsg =
- cat ( tag(UPB_TYPE(INT32), UPB_WIRE_TYPE_VARINT),
- buffer_new3(incompletes[UPB_WIRE_TYPE_VARINT]), NULL );
- assert_does_not_parse(
- cat( tag(fieldnum, UPB_WIRE_TYPE_DELIMITED),
- varint(incomplete_submsg->len),
- incomplete_submsg, NULL ));
- }
- } else {
- // Packed region ends in the middle of a value.
- assert_does_not_parse(
- cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
- varint(strlen(incomplete)),
- buffer_new3(incomplete), NULL ));
-
- // EOF in the middle of packed region.
- assert_does_not_parse_at_eof(
- cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED), varint(1), NULL ));
- }
-}
-
-// "33" and "66" are just two random values that all numeric types can
-// represent.
-void test_valid_data_for_type(upb_fieldtype_t type,
- buffer *enc33, buffer *enc66) {
- uint32_t fieldnum = type;
- uint32_t rep_fieldnum = rep_fn(type);
- int wire_type = upb_types[type].native_wire_type;
-
- // Non-repeated
- assert_successful_parse(
- cat( tag(fieldnum, wire_type), buffer_dup(enc33),
- tag(fieldnum, wire_type), buffer_dup(enc66), NULL ),
- "%u:33; %u:66; ", fieldnum, fieldnum);
-
- // Non-packed repeated.
- assert_successful_parse(
- cat( tag(rep_fieldnum, wire_type), buffer_dup(enc33),
- tag(rep_fieldnum, wire_type), buffer_dup(enc66), NULL ),
- "%u:[ %u:33; %u:66; ] ", rep_fieldnum, rep_fieldnum, rep_fieldnum);
-
- // Packed repeated.
- assert_successful_parse(
- cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
- delim(cat( buffer_dup(enc33), buffer_dup(enc66), NULL )), NULL ),
- "%u:[ %u:33; %u:66; ] ", rep_fieldnum, rep_fieldnum, rep_fieldnum);
-
- buffer_free(enc33);
- buffer_free(enc66);
-}
-
-void test_valid_data_for_signed_type(upb_fieldtype_t type,
- buffer *enc33, buffer *enc66) {
- uint32_t fieldnum = type;
- uint32_t rep_fieldnum = rep_fn(type);
- int wire_type = upb_types[type].native_wire_type;
-
- // Non-repeated
- assert_successful_parse(
- cat( tag(fieldnum, wire_type), buffer_dup(enc33),
- tag(fieldnum, wire_type), buffer_dup(enc66), NULL ),
- "%u:33; %u:-66; ", fieldnum, fieldnum);
-
- // Non-packed repeated.
- assert_successful_parse(
- cat( tag(rep_fieldnum, wire_type), buffer_dup(enc33),
- tag(rep_fieldnum, wire_type), buffer_dup(enc66), NULL ),
- "%u:[ %u:33; %u:-66; ] ", rep_fieldnum, rep_fieldnum, rep_fieldnum);
-
- // Packed repeated.
- assert_successful_parse(
- cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
- delim(cat( buffer_dup(enc33), buffer_dup(enc66), NULL )), NULL ),
- "%u:[ %u:33; %u:-66; ] ", rep_fieldnum, rep_fieldnum, rep_fieldnum);
-
- buffer_free(enc33);
- buffer_free(enc66);
-}
-
-// Test that invalid protobufs are properly detected (without crashing) and
-// have an error reported. Field numbers match registered handlers above.
-void test_invalid() {
- test_premature_eof_for_type(UPB_TYPE(DOUBLE));
- test_premature_eof_for_type(UPB_TYPE(FLOAT));
- test_premature_eof_for_type(UPB_TYPE(INT64));
- test_premature_eof_for_type(UPB_TYPE(UINT64));
- test_premature_eof_for_type(UPB_TYPE(INT32));
- test_premature_eof_for_type(UPB_TYPE(FIXED64));
- test_premature_eof_for_type(UPB_TYPE(FIXED32));
- test_premature_eof_for_type(UPB_TYPE(BOOL));
- test_premature_eof_for_type(UPB_TYPE(STRING));
- test_premature_eof_for_type(UPB_TYPE(BYTES));
- test_premature_eof_for_type(UPB_TYPE(UINT32));
- test_premature_eof_for_type(UPB_TYPE(ENUM));
- test_premature_eof_for_type(UPB_TYPE(SFIXED32));
- test_premature_eof_for_type(UPB_TYPE(SFIXED64));
- test_premature_eof_for_type(UPB_TYPE(SINT32));
- test_premature_eof_for_type(UPB_TYPE(SINT64));
-
- // EOF inside a tag's varint.
- assert_does_not_parse_at_eof( buffer_new3("\x80") );
-
- // EOF inside a known group.
- assert_does_not_parse_at_eof( tag(4, UPB_WIRE_TYPE_START_GROUP) );
-
- // EOF inside an unknown group.
- assert_does_not_parse_at_eof( tag(UNKNOWN_FIELD, UPB_WIRE_TYPE_START_GROUP) );
-
- // End group that we are not currently in.
- assert_does_not_parse( tag(4, UPB_WIRE_TYPE_END_GROUP) );
-
- // Field number is 0.
- assert_does_not_parse(
- cat( tag(0, UPB_WIRE_TYPE_DELIMITED), varint(0), NULL ));
-
- // Field number is too large.
- assert_does_not_parse(
- cat( tag(UPB_MAX_FIELDNUMBER + 1, UPB_WIRE_TYPE_DELIMITED),
- varint(0), NULL ));
-
- // Test exceeding the resource limit of stack depth.
- buffer *buf = buffer_new3("");
- for (int i = 0; i < UPB_MAX_NESTING; i++) {
- buf = submsg(UPB_TYPE(MESSAGE), buf);
- }
- assert_does_not_parse(buf);
-
- // Staying within the stack limit should work properly.
- buf = buffer_new3("");
- buffer *textbuf = buffer_new3("");
- int total = UPB_MAX_NESTING - 1;
- for (int i = 0; i < total; i++) {
- buf = submsg(UPB_TYPE(MESSAGE), buf);
- buffer_appendf(textbuf, "%u:{ ", UPB_TYPE(MESSAGE));
- }
- for (int i = 0; i < total; i++) {
- buffer_appendf(textbuf, "} ");
- }
- assert_successful_parse(buf, "%s", textbuf->buf);
- buffer_free(textbuf);
-}
-
-void test_valid() {
- test_valid_data_for_signed_type(UPB_TYPE(DOUBLE), dbl(33), dbl(-66));
- test_valid_data_for_signed_type(UPB_TYPE(FLOAT), flt(33), flt(-66));
- test_valid_data_for_signed_type(UPB_TYPE(INT64), varint(33), varint(-66));
- test_valid_data_for_signed_type(UPB_TYPE(INT32), varint(33), varint(-66));
- test_valid_data_for_signed_type(UPB_TYPE(ENUM), varint(33), varint(-66));
- test_valid_data_for_signed_type(UPB_TYPE(SFIXED32), uint32(33), uint32(-66));
- test_valid_data_for_signed_type(UPB_TYPE(SFIXED64), uint64(33), uint64(-66));
- test_valid_data_for_signed_type(UPB_TYPE(SINT32), zz32(33), zz32(-66));
- test_valid_data_for_signed_type(UPB_TYPE(SINT64), zz64(33), zz64(-66));
-
- test_valid_data_for_type(UPB_TYPE(UINT64), varint(33), varint(66));
- test_valid_data_for_type(UPB_TYPE(UINT32), varint(33), varint(66));
- test_valid_data_for_type(UPB_TYPE(FIXED64), uint64(33), uint64(66));
- test_valid_data_for_type(UPB_TYPE(FIXED32), uint32(33), uint32(66));
-
- // Submessage tests.
- uint32_t msg_fn = UPB_TYPE(MESSAGE);
- assert_successful_parse(
- submsg(msg_fn, submsg(msg_fn, submsg(msg_fn, buffer_new3("")))),
- "%u:{ %u:{ %u:{ } } } ", msg_fn, msg_fn, msg_fn);
-
- uint32_t repm_fn = rep_fn(UPB_TYPE(MESSAGE));
- assert_successful_parse(
- submsg(repm_fn, submsg(repm_fn, buffer_new3(""))),
- "%u:[ %u:{ %u:[ %u:{ } ] } ] ", repm_fn, repm_fn, repm_fn, repm_fn);
-}
-
-void run_tests() {
- test_invalid();
- test_valid();
-}
-
-int main() {
- // Construct decoder plan.
- upb_handlers *h = upb_handlers_new();
- reghandlers(upb_handlers_newmhandlers(h));
-
- // Test without JIT.
- plan = upb_decoderplan_new(h, false);
- run_tests();
- upb_decoderplan_unref(plan);
-
- // Test JIT.
- plan = upb_decoderplan_new(h, true);
- run_tests();
- upb_decoderplan_unref(plan);
-
- plan = NULL;
- printf("All tests passed, %d assertions.\n", num_assertions);
- upb_handlers_unref(h);
- return 0;
-}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback