/*! * Create a submessage within a message for a specific tag. * * \param[in,out] message Message * \param[in] tag Tag * \return Submessage */ extern pb_message_t pb_message_create_within(pb_message_t *message, pb_tag_t tag) { assert(message && tag); if (pb_message_valid(message)) { const pb_field_descriptor_t *descriptor = pb_descriptor_field_by_tag(message->descriptor, tag); assert(descriptor && pb_field_descriptor_type(descriptor) == PB_TYPE_MESSAGE && pb_field_descriptor_nested(descriptor)); pb_message_t submessage = { .descriptor = pb_field_descriptor_nested(descriptor), .part = pb_part_create(message, tag) }; return submessage; } return pb_message_create_invalid(); } /*! * Create a submessage within a nested message for a branch of tags. * * \warning All messages on the branch of tags except the leaf may not occur * repeatedly, but must be defined as optional or required. * * \param[in,out] message Message * \param[in] tags[] Tags * \param[in] size Tag count * \return Submessage */ extern pb_message_t pb_message_create_nested( pb_message_t *message, const pb_tag_t tags[], size_t size) { assert(message && tags && size); pb_message_t prev = pb_message_create_invalid(), this = pb_message_copy(message); for (size_t t = 0; t < size && pb_message_valid(&this); ++t) { pb_message_destroy(&prev); #ifndef NDEBUG /* Assert non-repeated non-leaf messages */ const pb_field_descriptor_t *descriptor = pb_descriptor_field_by_tag(this.descriptor, tags[t]); assert(descriptor && ( pb_field_descriptor_type(descriptor) == PB_TYPE_MESSAGE && ( pb_field_descriptor_label(descriptor) != PB_LABEL_REPEATED || t == size - 1))); #endif /* NDEBUG */ /* Swap messages and create a new one within */ prev = this; this = pb_message_create_within(&prev, tags[t]); } pb_message_destroy(&prev); return this; }
} END_TEST /* * Create a part from an invalid cursor. */ START_TEST(test_create_from_cursor_invalid) { pb_binary_t binary = pb_binary_create_empty(); pb_message_t message = pb_message_create(&descriptor, &binary); pb_cursor_t cursor = pb_cursor_create_invalid(); /* Assert cursor validity and error */ fail_if(pb_cursor_valid(&cursor)); ck_assert_uint_eq(PB_ERROR_INVALID, pb_cursor_error(&cursor)); /* Create part from cursor */ pb_part_t part = pb_part_create_from_cursor(&cursor); /* Assert part validity and error */ fail_if(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_INVALID, pb_part_error(&part)); /* Free all allocated memory */ pb_part_destroy(&part); pb_cursor_destroy(&cursor); pb_message_destroy(&message); pb_binary_destroy(&binary); } END_TEST
} END_TEST /* * Create a part from an empty message for a specific tag. */ START_TEST(test_create_message_empty) { pb_binary_t binary = pb_binary_create_empty(); pb_message_t message = pb_message_create(&descriptor, &binary); pb_part_t part = pb_part_create(&message, 1); /* Assert part validity and error */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_unless(pb_part_empty(&part)); ck_assert_uint_eq(0, pb_part_size(&part)); ck_assert_uint_eq(1, pb_part_version(&part)); /* Assert part offsets */ ck_assert_uint_eq(1, pb_part_start(&part)); ck_assert_uint_eq(1, pb_part_end(&part)); /* Assert binary size */ fail_if(pb_binary_empty(&binary)); ck_assert_uint_eq(1, pb_binary_size(&binary)); /* Free all allocated memory */ pb_part_destroy(&part); pb_message_destroy(&message); pb_binary_destroy(&binary); } END_TEST
} END_TEST /* * Create a part at the current position of a cursor. */ START_TEST(test_create_from_cursor) { pb_binary_t binary = pb_binary_create_empty(); pb_message_t message = pb_message_create(&descriptor, &binary); /* Create a hundred part siblings and write values to them */ for (size_t p = 1; p < 101; p++) { pb_part_t part = pb_part_create(&message, 10); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_write(&part, (uint8_t *)&p, 1)); /* Free all allocated memory */ pb_part_destroy(&part); } /* Create cursor */ pb_cursor_t cursor = pb_cursor_create(&message, 10); /* Assert cursor validity and error */ fail_unless(pb_cursor_valid(&cursor)); ck_assert_uint_eq(PB_ERROR_NONE, pb_cursor_error(&cursor)); /* Walk through parts */ for (size_t p = 1; p < 101; p++, pb_cursor_next(&cursor)) { pb_part_t part = pb_part_create_from_cursor(&cursor); /* Assert part validity and error */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_if(pb_part_empty(&part)); ck_assert_uint_eq(1, pb_part_size(&part)); ck_assert_uint_eq(200, pb_part_version(&part)); /* Assert part offsets */ ck_assert_uint_eq(p * 2 - 1, pb_part_start(&part)); ck_assert_uint_eq(p * 2, pb_part_end(&part)); /* Free all allocated memory */ pb_part_destroy(&part); } /* Assert cursor validity and error */ fail_if(pb_cursor_valid(&cursor)); ck_assert_uint_eq(PB_ERROR_OFFSET, pb_cursor_error(&cursor)); /* Free all allocated memory */ pb_cursor_destroy(&cursor); pb_message_destroy(&message); pb_binary_destroy(&binary); } END_TEST
} END_TEST /* * Write a string value to a part. */ START_TEST(test_write_string) { const uint8_t data[] = { 66, 9, 83, 79, 77, 69, 32, 68, 65, 84, 65 }; const size_t size = 11; /* Create binary, message and part */ pb_binary_t binary = pb_binary_create_empty(); pb_message_t message = pb_message_create(&descriptor, &binary); pb_part_t part = pb_part_create(&message, 8); /* Assert part validity and error */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_unless(pb_part_empty(&part)); ck_assert_uint_eq(0, pb_part_size(&part)); ck_assert_uint_eq(1, pb_part_version(&part)); /* Write value to part */ uint8_t value[] = "SOME DATA"; ck_assert_uint_eq(PB_ERROR_NONE, pb_part_write(&part, value, 9)); fail_if(memcmp(data, pb_binary_data(&binary), size)); /* Assert part validity and error again */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_if(pb_part_empty(&part)); ck_assert_uint_eq(9, pb_part_size(&part)); ck_assert_uint_eq(2, pb_part_version(&part)); /* Assert part offsets */ ck_assert_uint_eq(2, pb_part_start(&part)); ck_assert_uint_eq(11, pb_part_end(&part)); /* Assert binary size */ fail_if(pb_binary_empty(&binary)); ck_assert_uint_eq(11, pb_binary_size(&binary)); /* Free all allocated memory */ pb_part_destroy(&part); pb_message_destroy(&message); pb_binary_destroy(&binary); } END_TEST
} END_TEST /* * Write a value to a part. */ START_TEST(test_write) { uint8_t data[] = { 8, 127 }; size_t size = 2; /* Create binary, message and part */ pb_binary_t binary = pb_binary_create_empty(); pb_message_t message = pb_message_create(&descriptor, &binary); pb_part_t part = pb_part_create(&message, 1); /* Assert part validity and error */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_unless(pb_part_empty(&part)); ck_assert_uint_eq(0, pb_part_size(&part)); ck_assert_uint_eq(1, pb_part_version(&part)); /* Write value to part */ uint8_t value[] = { 127 }; ck_assert_uint_eq(PB_ERROR_NONE, pb_part_write(&part, value, 1)); fail_if(memcmp(data, pb_binary_data(&binary), size)); /* Assert part validity and error again */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_if(pb_part_empty(&part)); ck_assert_uint_eq(1, pb_part_size(&part)); ck_assert_uint_eq(2, pb_part_version(&part)); /* Assert part offsets */ ck_assert_uint_eq(1, pb_part_start(&part)); ck_assert_uint_eq(2, pb_part_end(&part)); /* Assert binary size */ fail_if(pb_binary_empty(&binary)); ck_assert_uint_eq(2, pb_binary_size(&binary)); /* Free all allocated memory */ pb_part_destroy(&part); pb_message_destroy(&message); pb_binary_destroy(&binary); } END_TEST
} END_TEST /* * Create a part from an invalid message for a specific tag. */ START_TEST(test_create_message_invalid) { pb_message_t message = pb_message_create_invalid(); pb_part_t part = pb_part_create(&message, 1); /* Assert part validity and error */ fail_if(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_INVALID, pb_part_error(&part)); /* Free all allocated memory */ pb_part_destroy(&part); pb_message_destroy(&message); } END_TEST
} END_TEST /* * Write a long string value to a part. */ START_TEST(test_write_string_long) { pb_binary_t binary = pb_binary_create_empty(); pb_message_t message = pb_message_create(&descriptor, &binary); pb_part_t part = pb_part_create(&message, 8); /* Assert part validity and error */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_unless(pb_part_empty(&part)); ck_assert_uint_eq(0, pb_part_size(&part)); ck_assert_uint_eq(1, pb_part_version(&part)); /* Write value to part */ pb_string_t value = pb_string_init( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam euismod " "vehicula nibh, et egestas erat eleifend quis. Nam hendrerit egestas " "quam nec egestas. Donec lacinia vestibulum erat, ac suscipit nisi " "vehicula nec. Praesent ullamcorper vitae lorem vel euismod. Quisque " "fringilla lobortis convallis. Aliquam accumsan lacus eu viverra dapibus. " "Phasellus in adipiscing sem, in congue massa. Vestibulum ullamcorper " "orci nec semper pretium."); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_write(&part, value.data, value.size)); /* Assert part validity and error again */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_if(pb_part_empty(&part)); ck_assert_uint_eq(437, pb_part_size(&part)); ck_assert_uint_eq(3, pb_part_version(&part)); /* Free all allocated memory */ pb_part_destroy(&part); pb_message_destroy(&message); pb_binary_destroy(&binary); } END_TEST
} END_TEST /* * Create a set of repeated parts within a message for a specific tag. */ START_TEST(test_create_repeated) { pb_binary_t binary = pb_binary_create_empty(); pb_message_t message = pb_message_create(&descriptor, &binary); /* Create a hundred parts and write values to them */ for (size_t p = 1; p < 101; p++) { pb_part_t part = pb_part_create(&message, 10); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_write(&part, (uint8_t *)&p, 1)); /* Assert part validity and error */ fail_unless(pb_part_valid(&part)); ck_assert_uint_eq(PB_ERROR_NONE, pb_part_error(&part)); /* Assert part size and version */ fail_if(pb_part_empty(&part)); ck_assert_uint_eq(1, pb_part_size(&part)); ck_assert_uint_eq(p * 2, pb_part_version(&part)); /* Assert part offsets */ ck_assert_uint_eq(p * 2 - 1, pb_part_start(&part)); ck_assert_uint_eq(p * 2, pb_part_end(&part)); /* Assert binary size */ fail_if(pb_binary_empty(&binary)); ck_assert_uint_eq(p * 2, pb_binary_size(&binary)); /* Free all allocated memory */ pb_part_destroy(&part); } /* Assert binary contents */ for (size_t p = 1; p < 101; p++) ck_assert_uint_eq(p, pb_binary_data_at(&binary, p * 2 - 1)); /* Free all allocated memory */ pb_message_destroy(&message); pb_binary_destroy(&binary); } END_TEST