TEST(WireFormat, StructRoundTrip_OneSegment) { Session ctx; setupStruct(&ctx.capn); // word count: // 1 root reference // 8 root struct // 1 sub message // 2 3-element int32 list // 13 struct list // 1 tag // 12 4x struct // 1 data segment // 1 reference segment // 1 sub-struct // 11 list list // 5 references to sub-lists // 6 sub-lists (4x 1 word, 1x 2 words) // 2 recurse // ----- // 38 ASSERT_EQ(1, ctx.capn.segnum); EXPECT_EQ(38*8, ctx.capn.seglist->len); checkStruct(&ctx.capn); struct capn ctx2; memset(&ctx2, 0, sizeof(ctx2)); capn_append_segment(&ctx2, ctx.capn.seglist); checkStruct(&ctx2); }
TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation_NoTag) { Session ctx; ctx.capn.create = &CreateSmallSegment; g_AddTag = 0; setupStruct(&ctx.capn); g_AddTag = 1; struct capn_segment *segments[31]; getSegments(&ctx.capn, segments, 31); // Check that each segment has the expected size. Note that we have plenty // of 16 byte double far ptrs. EXPECT_EQ( 8, segments[ 0]->len); // root ref EXPECT_EQ(64, segments[ 1]->len); // root struct EXPECT_EQ(16, segments[ 2]->len); // root struct ptr EXPECT_EQ( 8, segments[ 3]->len); // sub-struct EXPECT_EQ(16, segments[ 4]->len); // sub-struct ptr EXPECT_EQ(16, segments[ 5]->len); // 3-element int32 list EXPECT_EQ(16, segments[ 6]->len); // 3-element int32 list ptr EXPECT_EQ(72, segments[ 7]->len); // struct list EXPECT_EQ(16, segments[ 8]->len); // struct list ptr EXPECT_EQ( 8, segments[ 9]->len); // struct list substruct 1 EXPECT_EQ(16, segments[10]->len); // struct list substruct 1 ptr EXPECT_EQ( 8, segments[11]->len); // struct list substruct 2 EXPECT_EQ(16, segments[12]->len); // struct list substruct 2 ptr EXPECT_EQ( 8, segments[13]->len); // struct list substruct 3 EXPECT_EQ(16, segments[14]->len); // struct list substruct 3 ptr EXPECT_EQ( 8, segments[15]->len); // struct list substruct 4 EXPECT_EQ(16, segments[16]->len); // struct list substruct 4 ptr EXPECT_EQ(40, segments[17]->len); // list list EXPECT_EQ(16, segments[18]->len); // list list ptr EXPECT_EQ( 8, segments[19]->len); // list list sublist 1 EXPECT_EQ(16, segments[20]->len); // list list sublist 1 ptr EXPECT_EQ( 8, segments[21]->len); // list list sublist 2 EXPECT_EQ(16, segments[22]->len); // list list sublist 2 ptr EXPECT_EQ( 8, segments[23]->len); // list list sublist 3 EXPECT_EQ(16, segments[24]->len); // list list sublist 3 ptr EXPECT_EQ( 8, segments[25]->len); // list list sublist 4 EXPECT_EQ(16, segments[26]->len); // list list sublist 4 ptr EXPECT_EQ(16, segments[27]->len); // list list sublist 5 EXPECT_EQ(16, segments[28]->len); // list list sublist 5 ptr EXPECT_EQ(16, segments[29]->len); // recurse struct EXPECT_EQ(16, segments[30]->len); // recurse struct ptr checkStruct(&ctx.capn); struct capn ctx2; memset(&ctx2, 0, sizeof(ctx2)); for (int i = 0; i < sizeof(segments)/sizeof(segments[0]); i++) { capn_append_segment(&ctx2, segments[i]); } checkStruct(&ctx2); }
TEST(WireFormat, SimpleRawDataStruct) { AlignedData<2> data = {{ // Struct ref, offset = 1, dataSize = 1, referenceCount = 0 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // Content for the data segment. 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }}; struct capn_segment seg; memset(&seg, 0, sizeof(seg)); seg.data = (char*) data.bytes; seg.len = seg.cap = sizeof(data.bytes); struct capn ctx; memset(&ctx, 0, sizeof(ctx)); capn_append_segment(&ctx, &seg); EXPECT_EQ(&seg, ctx.seglist); EXPECT_EQ(&seg, ctx.lastseg); EXPECT_EQ(&seg.hdr, ctx.segtree); EXPECT_EQ(1, ctx.segnum); EXPECT_EQ(0, seg.id); struct capn_ptr ptr = capn_getp(capn_root(&ctx), 0, 1); EXPECT_EQ(CAPN_STRUCT, ptr.type); EXPECT_EQ(8, ptr.datasz); EXPECT_EQ(0, ptr.ptrs); EXPECT_EQ(UINT64_C(0xefcdab8967452301), capn_read64(ptr, 0)); EXPECT_EQ(UINT64_C(0), capn_read64(ptr, 8)); EXPECT_EQ(UINT32_C(0x67452301), capn_read32(ptr, 0)); EXPECT_EQ(UINT32_C(0xefcdab89), capn_read32(ptr, 4)); EXPECT_EQ(UINT32_C(0), capn_read32(ptr, 8)); EXPECT_EQ(UINT16_C(0x2301), capn_read16(ptr, 0)); EXPECT_EQ(UINT16_C(0x6745), capn_read16(ptr, 2)); EXPECT_EQ(UINT16_C(0xab89), capn_read16(ptr, 4)); EXPECT_EQ(UINT16_C(0xefcd), capn_read16(ptr, 6)); EXPECT_EQ(UINT16_C(0), capn_read16(ptr, 8)); }
TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) { Session ctx; ctx.capn.create = &CreateSegment64; setupStruct(&ctx.capn); // Verify that we made 6 segments. ASSERT_EQ(6, ctx.capn.segnum); struct capn_segment *segments[6]; segments[0] = ctx.capn.seglist; for (int i = 1; i < 6; i++) { segments[i] = segments[i-1]->next; } for (int i = 0; i < 6; i++) { EXPECT_EQ(segments[i]->id, i); } // Check that each segment has the expected size. Recall that each object will be prefixed by an // extra word if its parent is in a different segment. EXPECT_EQ(64, segments[0]->len); // root ref (8), sub-struct (8+tag), 3-element list (16+tag), list substruct 1 (8+tag) EXPECT_EQ(72, segments[1]->len); // root struct (64+tag) EXPECT_EQ(80, segments[2]->len); // struct list (72+tag) EXPECT_EQ(64, segments[3]->len); // list substruct 2,3,4 3*(8+tag), sublist 3 (8+tag) EXPECT_EQ(64, segments[4]->len); // list list (40+tag), sublist 1,2 2*8 EXPECT_EQ(64, segments[5]->len); // sublist 4 (8+tag), 5 (16+tag), recurse struct (16+tag) checkStruct(&ctx.capn); struct capn ctx2; memset(&ctx2, 0, sizeof(ctx2)); for (int i = 0; i < sizeof(segments)/sizeof(segments[0]); i++) { capn_append_segment(&ctx2, segments[i]); } checkStruct(&ctx2); }
TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) { Session ctx; ctx.capn.create = &CreateSmallSegment; setupStruct(&ctx.capn); struct capn_segment *segments[16]; getSegments(&ctx.capn, segments, 16); // Check that each segment has the expected size. Recall that the first word of each segment will // actually be a reference to the first thing allocated within that segment. EXPECT_EQ( 8, segments[ 0]->len); // root ref EXPECT_EQ(72, segments[ 1]->len); // root struct EXPECT_EQ(16, segments[ 2]->len); // sub-struct EXPECT_EQ(24, segments[ 3]->len); // 3-element int32 list EXPECT_EQ(80, segments[ 4]->len); // struct list EXPECT_EQ(16, segments[ 5]->len); // struct list substruct 1 EXPECT_EQ(16, segments[ 6]->len); // struct list substruct 2 EXPECT_EQ(16, segments[ 7]->len); // struct list substruct 3 EXPECT_EQ(16, segments[ 8]->len); // struct list substruct 4 EXPECT_EQ(48, segments[ 9]->len); // list list EXPECT_EQ(16, segments[10]->len); // list list sublist 1 EXPECT_EQ(16, segments[11]->len); // list list sublist 2 EXPECT_EQ(16, segments[12]->len); // list list sublist 3 EXPECT_EQ(16, segments[13]->len); // list list sublist 4 EXPECT_EQ(24, segments[14]->len); // list list sublist 5 EXPECT_EQ(24, segments[15]->len); // recurse struct checkStruct(&ctx.capn); struct capn ctx2; memset(&ctx2, 0, sizeof(ctx2)); for (int i = 0; i < sizeof(segments)/sizeof(segments[0]); i++) { capn_append_segment(&ctx2, segments[i]); } checkStruct(&ctx2); }
static int init_fp(struct capn *c, FILE *f, struct capn_stream *z, int packed) { /* * Initialize 'c' from the contents of 'f', assuming the message has been * serialized with the standard framing format. From https://capnproto.org/encoding.html: * * When transmitting over a stream, the following should be sent. All integers are unsigned and little-endian. * (4 bytes) The number of segments, minus one (since there is always at least one segment). * (N * 4 bytes) The size of each segment, in words. * (0 or 4 bytes) Padding up to the next word boundary. * The content of each segment, in order. */ struct capn_segment *s = NULL; uint32_t i, segnum, total = 0; uint32_t hdr[1024]; uint8_t zbuf[ZBUF_SZ]; char *data = NULL; capn_init_malloc(c); /* Read the first four bytes to know how many headers we have */ if (read_fp(&segnum, 4, f, z, zbuf, packed)) goto err; segnum = capn_flip32(segnum); if (segnum > 1023) goto err; segnum++; /* The wire encoding was zero-based */ /* Read the header list */ if (read_fp(hdr, 8 * (segnum/2) + 4, f, z, zbuf, packed)) goto err; for (i = 0; i < segnum; i++) { uint32_t n = capn_flip32(hdr[i]); if (n > INT_MAX/8 || n > UINT32_MAX/8 || UINT32_MAX - total < n*8) goto err; hdr[i] = n*8; total += hdr[i]; } /* Allocate space for the data and the capn_segment structs */ s = (struct capn_segment*) calloc(1, total + (sizeof(*s) * segnum)); if (!s) goto err; /* Now read the data and setup the capn_segment structs */ data = (char*) (s+segnum); if (read_fp(data, total, f, z, zbuf, packed)) goto err; for (i = 0; i < segnum; i++) { s[i].len = s[i].cap = hdr[i]; s[i].data = data; data += s[i].len; capn_append_segment(c, &s[i]); } /* Set the entire region to be freed on the last segment */ s[segnum-1].user = s; return 0; err: memset(c, 0, sizeof(*c)); free(s); return -1; }