1 // Copyright 2014 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 // Serialization warnings are only recorded when DLOG is enabled.
6 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
7
8 #include <stddef.h>
9 #include <utility>
10
11 #include "mojo/public/cpp/bindings/array.h"
12 #include "mojo/public/cpp/bindings/lib/array_internal.h"
13 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
14 #include "mojo/public/cpp/bindings/lib/serialization.h"
15 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
16 #include "mojo/public/cpp/bindings/string.h"
17 #include "mojo/public/cpp/system/message_pipe.h"
18 #include "mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom.h"
19 #include "mojo/public/interfaces/bindings/tests/test_unions.mojom.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace mojo {
23 namespace test {
24 namespace {
25
26 using mojo::internal::ContainerValidateParams;
27
28 // Creates an array of arrays of handles (2 X 3) for testing.
CreateTestNestedHandleArray()29 Array<Array<ScopedHandle>> CreateTestNestedHandleArray() {
30 Array<Array<ScopedHandle>> array(2);
31 for (size_t i = 0; i < array.size(); ++i) {
32 Array<ScopedHandle> nested_array(3);
33 for (size_t j = 0; j < nested_array.size(); ++j) {
34 MessagePipe pipe;
35 nested_array[j] = ScopedHandle::From(std::move(pipe.handle1));
36 }
37 array[i] = std::move(nested_array);
38 }
39
40 return array;
41 }
42
43 class SerializationWarningTest : public testing::Test {
44 public:
~SerializationWarningTest()45 ~SerializationWarningTest() override {}
46
47 protected:
48 template <typename T>
TestWarning(T obj,mojo::internal::ValidationError expected_warning)49 void TestWarning(T obj, mojo::internal::ValidationError expected_warning) {
50 warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE);
51
52 mojo::internal::SerializationContext context;
53 mojo::internal::FixedBufferForTesting buf(
54 mojo::internal::PrepareToSerialize<T>(obj, &context));
55 typename mojo::internal::MojomTypeTraits<T>::Data* data;
56 mojo::internal::Serialize<T>(obj, &buf, &data, &context);
57
58 EXPECT_EQ(expected_warning, warning_observer_.last_warning());
59 }
60
61 template <typename T>
TestArrayWarning(T obj,mojo::internal::ValidationError expected_warning,const ContainerValidateParams * validate_params)62 void TestArrayWarning(T obj,
63 mojo::internal::ValidationError expected_warning,
64 const ContainerValidateParams* validate_params) {
65 warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE);
66
67 mojo::internal::SerializationContext context;
68 mojo::internal::FixedBufferForTesting buf(
69 mojo::internal::PrepareToSerialize<T>(obj, &context));
70 typename mojo::internal::MojomTypeTraits<T>::Data* data;
71 mojo::internal::Serialize<T>(obj, &buf, &data, validate_params, &context);
72
73 EXPECT_EQ(expected_warning, warning_observer_.last_warning());
74 }
75
76 template <typename T>
TestUnionWarning(T obj,mojo::internal::ValidationError expected_warning)77 void TestUnionWarning(T obj,
78 mojo::internal::ValidationError expected_warning) {
79 warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE);
80
81 mojo::internal::SerializationContext context;
82 mojo::internal::FixedBufferForTesting buf(
83 mojo::internal::PrepareToSerialize<T>(obj, false, &context));
84 typename mojo::internal::MojomTypeTraits<T>::Data* data;
85 mojo::internal::Serialize<T>(obj, &buf, &data, false, &context);
86
87 EXPECT_EQ(expected_warning, warning_observer_.last_warning());
88 }
89
90 mojo::internal::SerializationWarningObserverForTesting warning_observer_;
91 };
92
TEST_F(SerializationWarningTest,HandleInStruct)93 TEST_F(SerializationWarningTest, HandleInStruct) {
94 Struct2Ptr test_struct(Struct2::New());
95 EXPECT_FALSE(test_struct->hdl.is_valid());
96
97 TestWarning(std::move(test_struct),
98 mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE);
99
100 test_struct = Struct2::New();
101 MessagePipe pipe;
102 test_struct->hdl = ScopedHandle::From(std::move(pipe.handle1));
103
104 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE);
105 }
106
TEST_F(SerializationWarningTest,StructInStruct)107 TEST_F(SerializationWarningTest, StructInStruct) {
108 Struct3Ptr test_struct(Struct3::New());
109 EXPECT_TRUE(!test_struct->struct_1);
110
111 TestWarning(std::move(test_struct),
112 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
113
114 test_struct = Struct3::New();
115 test_struct->struct_1 = Struct1::New();
116
117 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE);
118 }
119
TEST_F(SerializationWarningTest,ArrayOfStructsInStruct)120 TEST_F(SerializationWarningTest, ArrayOfStructsInStruct) {
121 Struct4Ptr test_struct(Struct4::New());
122 test_struct->data.resize(1);
123
124 TestWarning(std::move(test_struct),
125 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
126
127 test_struct = Struct4::New();
128 test_struct->data.resize(0);
129
130 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE);
131
132 test_struct = Struct4::New();
133 test_struct->data.resize(1);
134 test_struct->data[0] = Struct1::New();
135
136 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE);
137 }
138
TEST_F(SerializationWarningTest,FixedArrayOfStructsInStruct)139 TEST_F(SerializationWarningTest, FixedArrayOfStructsInStruct) {
140 Struct5Ptr test_struct(Struct5::New());
141 test_struct->pair.resize(1);
142 test_struct->pair[0] = Struct1::New();
143
144 TestWarning(std::move(test_struct),
145 mojo::internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
146
147 test_struct = Struct5::New();
148 test_struct->pair.resize(2);
149 test_struct->pair[0] = Struct1::New();
150 test_struct->pair[1] = Struct1::New();
151
152 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE);
153 }
154
TEST_F(SerializationWarningTest,ArrayOfArraysOfHandles)155 TEST_F(SerializationWarningTest, ArrayOfArraysOfHandles) {
156 Array<Array<ScopedHandle>> test_array = CreateTestNestedHandleArray();
157 test_array[0] = nullptr;
158 test_array[1][0] = ScopedHandle();
159
160 ContainerValidateParams validate_params_0(
161 0, true, new ContainerValidateParams(0, true, nullptr));
162 TestArrayWarning(std::move(test_array), mojo::internal::VALIDATION_ERROR_NONE,
163 &validate_params_0);
164
165 test_array = CreateTestNestedHandleArray();
166 test_array[0] = nullptr;
167 ContainerValidateParams validate_params_1(
168 0, false, new ContainerValidateParams(0, true, nullptr));
169 TestArrayWarning(std::move(test_array),
170 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
171 &validate_params_1);
172
173 test_array = CreateTestNestedHandleArray();
174 test_array[1][0] = ScopedHandle();
175 ContainerValidateParams validate_params_2(
176 0, true, new ContainerValidateParams(0, false, nullptr));
177 TestArrayWarning(std::move(test_array),
178 mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
179 &validate_params_2);
180 }
181
TEST_F(SerializationWarningTest,ArrayOfStrings)182 TEST_F(SerializationWarningTest, ArrayOfStrings) {
183 Array<String> test_array(3);
184 for (size_t i = 0; i < test_array.size(); ++i)
185 test_array[i] = "hello";
186
187 ContainerValidateParams validate_params_0(
188 0, true, new ContainerValidateParams(0, false, nullptr));
189 TestArrayWarning(std::move(test_array), mojo::internal::VALIDATION_ERROR_NONE,
190 &validate_params_0);
191
192 test_array = Array<String>(3);
193 for (size_t i = 0; i < test_array.size(); ++i)
194 test_array[i] = nullptr;
195 ContainerValidateParams validate_params_1(
196 0, false, new ContainerValidateParams(0, false, nullptr));
197 TestArrayWarning(std::move(test_array),
198 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
199 &validate_params_1);
200
201 test_array = Array<String>(2);
202 ContainerValidateParams validate_params_2(
203 3, true, new ContainerValidateParams(0, false, nullptr));
204 TestArrayWarning(std::move(test_array),
205 mojo::internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
206 &validate_params_2);
207 }
208
TEST_F(SerializationWarningTest,StructInUnion)209 TEST_F(SerializationWarningTest, StructInUnion) {
210 DummyStructPtr dummy(nullptr);
211 ObjectUnionPtr obj(ObjectUnion::New());
212 obj->set_f_dummy(std::move(dummy));
213
214 TestUnionWarning(std::move(obj),
215 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
216 }
217
TEST_F(SerializationWarningTest,UnionInUnion)218 TEST_F(SerializationWarningTest, UnionInUnion) {
219 PodUnionPtr pod(nullptr);
220 ObjectUnionPtr obj(ObjectUnion::New());
221 obj->set_f_pod_union(std::move(pod));
222
223 TestUnionWarning(std::move(obj),
224 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
225 }
226
TEST_F(SerializationWarningTest,HandleInUnion)227 TEST_F(SerializationWarningTest, HandleInUnion) {
228 ScopedMessagePipeHandle pipe;
229 HandleUnionPtr handle(HandleUnion::New());
230 handle->set_f_message_pipe(std::move(pipe));
231
232 TestUnionWarning(std::move(handle),
233 mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE);
234 }
235
236 } // namespace
237 } // namespace test
238 } // namespace mojo
239
240 #endif
241