| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "gtest/gtest.h" | |
| 6 #include "mojo/public/cpp/bindings/array.h" | |
| 7 #include "mojo/public/cpp/bindings/lib/array_serialization.h" | |
| 8 #include "mojo/public/cpp/bindings/lib/validation_errors.h" | |
| 9 #include "mojo/public/cpp/system/message_pipe.h" | |
| 10 #include "mojo/public/interfaces/bindings/tests/rect.mojom.h" | |
| 11 #include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h" | |
| 12 | |
| 13 namespace mojo { | |
| 14 namespace test { | |
| 15 namespace { | |
| 16 | |
| 17 class StructSerializationAPITest : public testing::Test { | |
| 18 public: | |
| 19 // We Serialize and Deserialize the given |Type|, and expect the given | |
| 20 // serialization warnings. We also validate (and expect a given error) in | |
| 21 // between serialization and deserialization. | |
| 22 template <typename Type> | |
| 23 void SerializeAndDeserialize( | |
| 24 Type* val, | |
| 25 mojo::internal::ValidationError expected_validation_error) { | |
| 26 size_t bytes_written = 0; | |
| 27 size_t num_bytes = val->GetSerializedSize(); | |
| 28 std::vector<uint8_t> bytes(num_bytes + 1); | |
| 29 | |
| 30 // Last byte is a magic value, helps catch a buffer overflow for | |
| 31 // serialization. | |
| 32 bytes[num_bytes] = 170; | |
| 33 val->Serialize(bytes.data(), num_bytes, &bytes_written); | |
| 34 EXPECT_EQ(170u, bytes[num_bytes]); | |
| 35 EXPECT_EQ(num_bytes, bytes_written); | |
| 36 | |
| 37 mojo::internal::BoundsChecker bounds_checker(bytes.data(), num_bytes, 0); | |
| 38 auto actual_validation_error = | |
| 39 Type::Data_::Validate(bytes.data(), &bounds_checker, nullptr); | |
| 40 EXPECT_EQ(expected_validation_error, actual_validation_error); | |
| 41 | |
| 42 Type out_val; | |
| 43 bool deserialize_ret = out_val.Deserialize(bytes.data(), bytes.size()); | |
| 44 if (actual_validation_error == mojo::internal::ValidationError::NONE) { | |
| 45 EXPECT_TRUE(val->Equals(out_val)); | |
| 46 } | |
| 47 EXPECT_EQ(actual_validation_error == mojo::internal::ValidationError::NONE, | |
| 48 deserialize_ret); | |
| 49 } | |
| 50 }; | |
| 51 | |
| 52 TEST_F(StructSerializationAPITest, GetSerializedSize) { | |
| 53 Rect rect; | |
| 54 // 8 byte struct header | |
| 55 // + 16 bytes worth of fields | |
| 56 EXPECT_EQ(24u, rect.GetSerializedSize()); | |
| 57 | |
| 58 HandleStruct handle_struct; | |
| 59 // 8 byte struct header | |
| 60 // + 4 byte handle | |
| 61 // + 8 bytes for offset/pointer for Array. | |
| 62 // + 0 bytes for uninitialized Array. | |
| 63 // + 4-byte to make the struct 8-byte aligned. | |
| 64 EXPECT_EQ(24u, handle_struct.GetSerializedSize()); | |
| 65 | |
| 66 // + 8 bytes for initialized array, 0-sized array. | |
| 67 handle_struct.array_h = mojo::Array<mojo::ScopedMessagePipeHandle>::New(0); | |
| 68 EXPECT_EQ(32u, handle_struct.GetSerializedSize()); | |
| 69 | |
| 70 // + 4 bytes for array of size 1. | |
| 71 // + 4 more bytes to make the array serialization 8-byte aligned. | |
| 72 handle_struct.array_h = mojo::Array<mojo::ScopedMessagePipeHandle>::New(1); | |
| 73 EXPECT_EQ(16u, GetSerializedSize_(handle_struct.array_h)); | |
| 74 EXPECT_EQ(40u, handle_struct.GetSerializedSize()); | |
| 75 } | |
| 76 | |
| 77 TEST_F(StructSerializationAPITest, BasicStructSerialization) { | |
| 78 { | |
| 79 SCOPED_TRACE("Rect"); | |
| 80 Rect rect; | |
| 81 rect.x = 123; | |
| 82 rect.y = 456; | |
| 83 rect.width = 789; | |
| 84 rect.height = 999; | |
| 85 SerializeAndDeserialize(&rect, mojo::internal::ValidationError::NONE); | |
| 86 } | |
| 87 | |
| 88 { | |
| 89 SCOPED_TRACE("DefaultFieldValues"); | |
| 90 DefaultFieldValues default_values; | |
| 91 SerializeAndDeserialize(&default_values, | |
| 92 mojo::internal::ValidationError::NONE); | |
| 93 } | |
| 94 | |
| 95 { | |
| 96 SCOPED_TRACE("NoDefaultFieldValues.Serialize() should fail"); | |
| 97 NoDefaultFieldValues nd; | |
| 98 nd.f0 = true; | |
| 99 nd.f23 = mojo::Array<mojo::String>::New(10); | |
| 100 | |
| 101 char buf[1000] = {}; | |
| 102 EXPECT_FALSE(nd.Serialize(buf, sizeof(buf))); | |
| 103 | |
| 104 size_t bytes_written = 0; | |
| 105 EXPECT_FALSE(nd.Serialize(buf, sizeof(buf), &bytes_written)); | |
| 106 EXPECT_EQ(160UL, bytes_written); | |
| 107 // The Serialize() shouldn't get around to reserving space for the |f23| | |
| 108 // array field. | |
| 109 EXPECT_LT(bytes_written, nd.GetSerializedSize()); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 // This tests serialization of handles -- These should be deaths or | |
| 114 TEST_F(StructSerializationAPITest, HandlesSerialization) { | |
| 115 { | |
| 116 SCOPED_TRACE("Uninitialized Array"); | |
| 117 HandleStruct handle_struct; | |
| 118 // TODO(vardhan): Once handles and pointers are encoded inline with | |
| 119 // serialization, validation should fail at | |
| 120 // ValidationError::UNEXPECTED_NULL_POINTER (which happens after the | |
| 121 // ValidationError::ILLEGAL_HANDLE error, which shouldn't happen since | |
| 122 // handles will be encoded even on failures). | |
| 123 SerializeAndDeserialize(&handle_struct, | |
| 124 mojo::internal::ValidationError::ILLEGAL_HANDLE); | |
| 125 } | |
| 126 | |
| 127 { | |
| 128 SCOPED_TRACE("Uninitialized required Handle in an Array"); | |
| 129 HandleStruct handle_struct; | |
| 130 handle_struct.array_h = Array<mojo::ScopedMessagePipeHandle>::New(1); | |
| 131 // This won't die (i.e., we don't need to EXPECT_DEATH) because the handle | |
| 132 // is invalid, so should be serializable. Instead, we live with a | |
| 133 // serialization error for an invalid handle. | |
| 134 // TODO(vardhan): This should be | |
| 135 // mojo::internal::ValidationError::UNEXPECTED_INVALID_HANDLE after handles | |
| 136 // are encoded inline with serialization. | |
| 137 SerializeAndDeserialize(&handle_struct, | |
| 138 mojo::internal::ValidationError::ILLEGAL_HANDLE); | |
| 139 } | |
| 140 | |
| 141 // We shouldn't be able to serialize a valid handle. | |
| 142 { | |
| 143 SCOPED_TRACE("Serializing a Handle"); | |
| 144 HandleStruct handle_struct; | |
| 145 handle_struct.h = MessagePipe().handle0.Pass(); | |
| 146 handle_struct.array_h = Array<mojo::ScopedMessagePipeHandle>::New(0); | |
| 147 EXPECT_DEATH_IF_SUPPORTED({ | |
| 148 SerializeAndDeserialize(&handle_struct, | |
| 149 mojo::internal::ValidationError::NONE); | |
| 150 }, "does not support handles"); | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 // We should be able to Serialize/Deserialize a struct that has a nullable | |
| 155 // handle which is null. | |
| 156 TEST_F(StructSerializationAPITest, NullableHandleSerialization) { | |
| 157 NullableHandleStruct handle_struct; | |
| 158 handle_struct.data = 16; | |
| 159 SerializeAndDeserialize(&handle_struct, | |
| 160 mojo::internal::ValidationError::NONE); | |
| 161 } | |
| 162 | |
| 163 // Test that |Deserialize()| appropriately fails on validation. | |
| 164 TEST_F(StructSerializationAPITest, DeserializationFailure) { | |
| 165 char buf[100] = {}; | |
| 166 EmptyStruct es; | |
| 167 | |
| 168 // Bounds checker should fail this, since buf_size is too small. | |
| 169 EXPECT_FALSE(es.Deserialize(buf, 1)); | |
| 170 | |
| 171 es.Serialize(buf, sizeof(buf)); | |
| 172 EXPECT_TRUE(es.Deserialize(buf, sizeof(buf))); | |
| 173 | |
| 174 // Invalid struct header: this should happen inside | |
| 175 // EmptyStruct::Data_::Validate()). | |
| 176 es.Serialize(buf, sizeof(buf)); | |
| 177 EmptyStruct::Data_* es_data = reinterpret_cast<EmptyStruct::Data_*>(buf); | |
| 178 es_data->header_.num_bytes = 0; | |
| 179 EXPECT_FALSE(es.Deserialize(buf, sizeof(buf))); | |
| 180 } | |
| 181 | |
| 182 TEST_F(StructSerializationAPITest, DeserializationWithoutValidation) { | |
| 183 const int32_t kMagic = 456; | |
| 184 char buf[100] = {}; | |
| 185 ContainsOther::Data_* co_data = reinterpret_cast<ContainsOther::Data_*>(buf); | |
| 186 ContainsOther co; | |
| 187 | |
| 188 // Success case. | |
| 189 co.other = kMagic; | |
| 190 EXPECT_TRUE(co.Serialize(buf, sizeof(buf))); | |
| 191 co.other = 0; | |
| 192 co.DeserializeWithoutValidation(buf); | |
| 193 EXPECT_EQ(kMagic, co.other); | |
| 194 | |
| 195 // Invalid struct header, but will pass (i.e., won't crash) anyway because we | |
| 196 // don't Validate. | |
| 197 co_data->header_.num_bytes = 0u; | |
| 198 co.DeserializeWithoutValidation(buf); | |
| 199 EXPECT_EQ(kMagic, co_data->other); | |
| 200 EXPECT_EQ(0u, co_data->header_.num_bytes); | |
| 201 } | |
| 202 | |
| 203 } // namespace | |
| 204 } // namespace test | |
| 205 } // namespace mojo | |
| OLD | NEW |