blob: 7ac249480d3d17691e92155afc3348a84056824b [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(vardhan): Needs a lot more testing.
#include <mojo/bindings/array.h>
#include <mojo/bindings/struct.h>
#include <stddef.h>
#include "mojo/public/c/tests/bindings/testing_util.h"
#include "mojo/public/cpp/system/macros.h"
#include "mojo/public/interfaces/bindings/tests/test_structs.mojom-c.h"
#include "mojo/public/interfaces/bindings/tests/test_unions.mojom-c.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// Tests MojomArray_New().
TEST(ArrayTest, New) {
char bytes_buffer[1000];
struct MojomBuffer buf = {bytes_buffer, sizeof(bytes_buffer), 0};
struct MojomArrayHeader* arr = NULL;
arr = MojomArray_New(&buf, 3, sizeof(uint32_t));
EXPECT_EQ(buf.buf, (char*)arr);
// Test that things are rounded up if data is not already multiple-of-8.
EXPECT_EQ(8u // array header
+ 3 * sizeof(uint32_t) // space for 3 uint32_ts.
+ 4u, // padding to round up to 8 bytes.
buf.num_bytes_used);
EXPECT_EQ(buf.num_bytes_used, arr->num_bytes);
EXPECT_EQ(3ul, arr->num_elements);
// Test failure when we try to allocate too much.
EXPECT_EQ(NULL, MojomArray_New(&buf, UINT32_MAX, sizeof(uint32_t)));
EXPECT_EQ(NULL, MojomArray_New(&buf, 1000, sizeof(uint32_t)));
// Test the simple case (no rounding necessary).
buf.num_bytes_used = 0;
arr = MojomArray_New(&buf, 4, sizeof(uint32_t));
EXPECT_EQ(8u // array header
+ 4 * sizeof(uint32_t), // space for 4 uint32_ts
buf.num_bytes_used);
EXPECT_EQ(buf.num_bytes_used, arr->num_bytes);
EXPECT_EQ(4ul, arr->num_elements);
}
// Tests serialized size of an array of unions.
TEST(ArraySerializationTest, ArrayOfUnions) {
char bytes_buffer[1000] = {0};
MojomBuffer buf = {bytes_buffer, sizeof(bytes_buffer), 0};
struct mojo_test_SmallStruct* small_struct =
static_cast<struct mojo_test_SmallStruct*>(
MojomBuffer_Allocate(&buf, sizeof(struct mojo_test_SmallStruct)));
*small_struct = mojo_test_SmallStruct{
// header
{
sizeof(mojo_test_SmallStruct),
0, // version
},
{NULL}, // dummy_struct
{0, mojo_test_PodUnion_Tag__UNKNOWN__, {}}, // pod_union
{NULL}, // pod_union_array
{NULL}, // nullable_pod_union_array
{NULL}, // s_array
{NULL}, // pod_union_map
{NULL}, // nullable_pod_union_map
};
EXPECT_EQ(8u + 6 * 8u // 6 references types
+ 1 * 16u, // 1 union type
mojo_test_SmallStruct_ComputeSerializedSize(small_struct));
small_struct->nullable_pod_union_array.ptr =
MojomArray_New(&buf, 2, sizeof(struct mojo_test_PodUnion));
// 0th element is NULL.
MOJOM_ARRAY_INDEX(small_struct->nullable_pod_union_array.ptr,
struct mojo_test_PodUnion, 0)
->size = 0;
// 1st element is not NULL.
struct mojo_test_PodUnion* e1 = MOJOM_ARRAY_INDEX(
small_struct->nullable_pod_union_array.ptr, struct mojo_test_PodUnion, 0);
e1->size = sizeof(struct mojo_test_PodUnion);
e1->tag = mojo_test_PodUnion_Tag_f_int8;
e1->data.f_f_int8 = 13;
EXPECT_EQ(8u + 6 * 8u // 6 references types
+ 1 * 16u // 1 union type
+ (8u + 16u * 2), // array of 2 unions
mojo_test_SmallStruct_ComputeSerializedSize(small_struct));
// Save the underlying buffer before encoding, so we can decode+compare
// later.
char bytes_buffer_copy[sizeof(bytes_buffer)];
memcpy(bytes_buffer_copy, bytes_buffer, sizeof(bytes_buffer));
mojo_test_SmallStruct_EncodePointersAndHandles(small_struct,
buf.num_bytes_used, NULL);
// The null pointers should now be 0-offsets:
EXPECT_EQ(0u, small_struct->dummy_struct.offset);
EXPECT_EQ(0u, small_struct->pod_union_array.offset);
EXPECT_EQ(0u, small_struct->s_array.offset);
EXPECT_EQ(0u, small_struct->pod_union_map.offset);
EXPECT_EQ(0u, small_struct->nullable_pod_union_map.offset);
// Test the pod_union_array offset:
EXPECT_EQ(
sizeof(struct mojo_test_SmallStruct) -
offsetof(struct mojo_test_SmallStruct, nullable_pod_union_array),
small_struct->nullable_pod_union_array.offset);
mojo_test_SmallStruct_DecodePointersAndHandles(small_struct,
buf.num_bytes_used, NULL, 0);
EXPECT_EQ(0, memcmp(buf.buf, bytes_buffer_copy, buf.num_bytes_used));
{
char bytes_buffer2[sizeof(bytes_buffer)] = {0};
struct MojomBuffer buf2 = {bytes_buffer2, sizeof(bytes_buffer2), 0};
CopyAndCompare(&buf2, small_struct, buf.num_bytes_used,
mojo_test_SmallStruct_DeepCopy,
mojo_test_SmallStruct_EncodePointersAndHandles,
mojo_test_SmallStruct_DecodePointersAndHandles);
}
}
// Tests serialized size of an array of arrays.
TEST(ArraySerializationTest, ArrayOfArrays) {
char bytes_buffer[1000] = {0};
MojomBuffer buf = {bytes_buffer, sizeof(bytes_buffer), 0};
struct mojo_test_ArrayOfArrays* arr =
static_cast<struct mojo_test_ArrayOfArrays*>(
MojomBuffer_Allocate(&buf, sizeof(struct mojo_test_ArrayOfArrays)));
*arr = mojo_test_ArrayOfArrays{
// header
{
sizeof(struct mojo_test_ArrayOfArrays), 0,
},
{NULL},
{NULL},
};
auto* a_array = MojomArray_New(&buf, 2, sizeof(union MojomArrayHeaderPtr));
arr->a.ptr = a_array;
MOJOM_ARRAY_INDEX(arr->a.ptr, union MojomArrayHeaderPtr, 0)->ptr = NULL;
MOJOM_ARRAY_INDEX(arr->a.ptr, union MojomArrayHeaderPtr, 1)->ptr = NULL;
EXPECT_EQ(24u + (8u + 2 * 8u) // a (with 2 null arrays)
+ 0u, // b (null altogether)
mojo_test_ArrayOfArrays_ComputeSerializedSize(arr));
// fill in |a| with array<int32> of size 2.
struct MojomArrayHeader* array_int32 =
MojomArray_New(&buf, 2, sizeof(int32_t));
MOJOM_ARRAY_INDEX(arr->a.ptr, union MojomArrayHeaderPtr, 0)
->ptr = array_int32;
*MOJOM_ARRAY_INDEX(array_int32, int32_t, 0) = 13;
*MOJOM_ARRAY_INDEX(array_int32, int32_t, 1) = 13;
EXPECT_EQ(24u + (8u + 2 * 8u) // a (with 2 arrays, 1 of them NULL)
+ 0u // b (null altogether)
+ (8u + 8u), // first array<int> in a
mojo_test_ArrayOfArrays_ComputeSerializedSize(arr));
// Save the underlying buffer before encoding, so we can decode+compare
// later.
char bytes_buffer_copy[sizeof(bytes_buffer)];
memcpy(bytes_buffer_copy, bytes_buffer, sizeof(bytes_buffer));
mojo_test_ArrayOfArrays_EncodePointersAndHandles(arr, buf.num_bytes_used,
NULL);
EXPECT_EQ(sizeof(struct mojo_test_ArrayOfArrays) -
offsetof(struct mojo_test_ArrayOfArrays, a),
arr->a.offset);
// Array of int32 should occur at the end of the array of 2 arrays -- so the
// offset is 2 pointer-sizes (1st one pointers to the array of int32, second
// one is NULL).
EXPECT_EQ(2 * sizeof(union MojomArrayHeaderPtr),
MOJOM_ARRAY_INDEX(a_array, union MojomArrayHeaderPtr, 0)->offset);
EXPECT_EQ(0u,
MOJOM_ARRAY_INDEX(a_array, union MojomArrayHeaderPtr, 1)->offset);
mojo_test_ArrayOfArrays_DecodePointersAndHandles(arr, buf.num_bytes_used,
NULL, 0);
EXPECT_EQ(0, memcmp(buf.buf, bytes_buffer_copy, buf.num_bytes_used));
{
char bytes_buffer2[sizeof(bytes_buffer)] = {0};
struct MojomBuffer buf2 = {bytes_buffer2, sizeof(bytes_buffer2), 0};
CopyAndCompare(&buf2, arr, buf.num_bytes_used,
mojo_test_ArrayOfArrays_DeepCopy,
mojo_test_ArrayOfArrays_EncodePointersAndHandles,
mojo_test_ArrayOfArrays_DecodePointersAndHandles);
}
}
// Tests serialization of an array of handles.
TEST(ArraySerializationTest, ArrayOfHandles) {
char buffer_bytes[1000] = {0};
MojomBuffer buf = {buffer_bytes, sizeof(buffer_bytes), 0};
struct mojo_test_StructWithNullableHandles* handle_struct =
static_cast<struct mojo_test_StructWithNullableHandles*>(
MojomBuffer_Allocate(
&buf, sizeof(struct mojo_test_StructWithNullableHandles)));
*handle_struct = mojo_test_StructWithNullableHandles{
// header
{sizeof(struct mojo_test_StructWithNullableHandles), 0},
// These fields will be initialized below.
MOJO_HANDLE_INVALID,
{0},
{NULL},
};
handle_struct->h = 10;
auto* array_h = MojomArray_New(&buf, 3, sizeof(MojoHandle));
handle_struct->array_h.ptr = array_h;
*MOJOM_ARRAY_INDEX(handle_struct->array_h.ptr, MojoHandle, 0) = 20;
*MOJOM_ARRAY_INDEX(handle_struct->array_h.ptr, MojoHandle, 1) =
MOJO_HANDLE_INVALID;
*MOJOM_ARRAY_INDEX(handle_struct->array_h.ptr, MojoHandle, 2) = 30;
EXPECT_EQ(
8u + 4u + 4u + 8u + 4u + (8u + 3 * 4u),
mojo_test_StructWithNullableHandles_ComputeSerializedSize(handle_struct));
// Save the underlying buffer before encoding, so we can decode+compare
// later.
char buffer_bytes_copy[sizeof(buffer_bytes)];
memcpy(buffer_bytes_copy, buffer_bytes, sizeof(buffer_bytes));
MojoHandle handles[5] = {};
struct MojomHandleBuffer handle_buf = {handles, MOJO_ARRAYSIZE(handles), 0u};
mojo_test_StructWithNullableHandles_EncodePointersAndHandles(
handle_struct, buf.num_bytes_used, &handle_buf);
EXPECT_EQ(3u, handle_buf.num_handles_used);
EXPECT_EQ(static_cast<MojoHandle>(10u), handles[0]);
EXPECT_EQ(static_cast<MojoHandle>(20u), handles[1]);
EXPECT_EQ(static_cast<MojoHandle>(30u), handles[2]);
EXPECT_EQ(0u, handle_struct->h);
EXPECT_EQ(1u, *MOJOM_ARRAY_INDEX(array_h, MojoHandle, 0));
EXPECT_EQ(static_cast<MojoHandle>(-1),
*MOJOM_ARRAY_INDEX(array_h, MojoHandle, 1));
EXPECT_EQ(2u, *MOJOM_ARRAY_INDEX(array_h, MojoHandle, 2));
EXPECT_EQ(sizeof(struct mojo_test_StructWithNullableHandles) -
offsetof(struct mojo_test_StructWithNullableHandles, array_h),
handle_struct->array_h.offset);
mojo_test_StructWithNullableHandles_DecodePointersAndHandles(
handle_struct, buf.num_bytes_used, handles, MOJO_ARRAYSIZE(handles));
EXPECT_EQ(0, memcmp(buf.buf, buffer_bytes_copy, buf.num_bytes_used));
// Check that the handles in the handles array are invalidated:
EXPECT_EQ(MOJO_HANDLE_INVALID, handles[0]);
EXPECT_EQ(MOJO_HANDLE_INVALID, handles[1]);
EXPECT_EQ(MOJO_HANDLE_INVALID, handles[2]);
{
char buffer_bytes2[sizeof(buffer_bytes)] = {0};
struct MojomBuffer buf2 = {buffer_bytes2, sizeof(buffer_bytes2), 0};
auto* copied_struct =
mojo_test_StructWithNullableHandles_DeepCopy(&buf2, handle_struct);
// The copy should still have the handles.
EXPECT_EQ(static_cast<MojoHandle>(10u), handle_struct->h);
EXPECT_EQ(static_cast<MojoHandle>(20u),
*MOJOM_ARRAY_INDEX(handle_struct->array_h.ptr, MojoHandle, 0));
EXPECT_EQ(MOJO_HANDLE_INVALID,
*MOJOM_ARRAY_INDEX(handle_struct->array_h.ptr, MojoHandle, 1));
EXPECT_EQ(static_cast<MojoHandle>(30u),
*MOJOM_ARRAY_INDEX(handle_struct->array_h.ptr, MojoHandle, 2));
// The new struct should have the handles now:
EXPECT_EQ(static_cast<MojoHandle>(10u), copied_struct->h);
EXPECT_EQ(static_cast<MojoHandle>(20u),
*MOJOM_ARRAY_INDEX(copied_struct->array_h.ptr, MojoHandle, 0));
EXPECT_EQ(MOJO_HANDLE_INVALID,
*MOJOM_ARRAY_INDEX(copied_struct->array_h.ptr, MojoHandle, 1));
EXPECT_EQ(static_cast<MojoHandle>(30u),
*MOJOM_ARRAY_INDEX(copied_struct->array_h.ptr, MojoHandle, 2));
}
}
} // namespace