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#include "mojo/public/cpp/bindings/array.h"
6#include "mojo/public/cpp/bindings/lib/array_internal.h"
7#include "mojo/public/cpp/bindings/lib/array_serialization.h"
8#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
9#include "mojo/public/cpp/environment/environment.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace mojo {
13namespace test {
14namespace {
15
16class CopyableType {
17 public:
18  CopyableType() : copied_(false), ptr_(this) { num_instances_++; }
19  CopyableType(const CopyableType& other) : copied_(true), ptr_(other.ptr()) {
20    num_instances_++;
21  }
22  CopyableType& operator=(const CopyableType& other) {
23    copied_ = true;
24    ptr_ = other.ptr();
25    return *this;
26  }
27  ~CopyableType() { num_instances_--; }
28
29  bool copied() const { return copied_; }
30  static size_t num_instances() { return num_instances_; }
31  CopyableType* ptr() const { return ptr_; }
32  void ResetCopied() { copied_ = false; }
33
34 private:
35  bool copied_;
36  static size_t num_instances_;
37  CopyableType* ptr_;
38};
39
40size_t CopyableType::num_instances_ = 0;
41
42class MoveOnlyType {
43  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(MoveOnlyType, RValue)
44 public:
45  typedef MoveOnlyType Data_;
46  MoveOnlyType() : moved_(false), ptr_(this) { num_instances_++; }
47  MoveOnlyType(RValue other) : moved_(true), ptr_(other.object->ptr()) {
48    num_instances_++;
49  }
50  MoveOnlyType& operator=(RValue other) {
51    moved_ = true;
52    ptr_ = other.object->ptr();
53    return *this;
54  }
55  ~MoveOnlyType() { num_instances_--; }
56
57  bool moved() const { return moved_; }
58  static size_t num_instances() { return num_instances_; }
59  MoveOnlyType* ptr() const { return ptr_; }
60  void ResetMoved() { moved_ = false; }
61
62 private:
63  bool moved_;
64  static size_t num_instances_;
65  MoveOnlyType* ptr_;
66};
67
68size_t MoveOnlyType::num_instances_ = 0;
69
70class ArrayTest : public testing::Test {
71 public:
72  virtual ~ArrayTest() {}
73
74 private:
75  Environment env_;
76};
77
78// Tests that basic Array operations work.
79TEST_F(ArrayTest, Basic) {
80  Array<char> array(8);
81  for (size_t i = 0; i < array.size(); ++i) {
82    char val = static_cast<char>(i*2);
83    array[i] = val;
84    EXPECT_EQ(val, array.at(i));
85  }
86}
87
88// Tests that basic Array<bool> operations work.
89TEST_F(ArrayTest, Bool) {
90  Array<bool> array(64);
91  for (size_t i = 0; i < array.size(); ++i) {
92    bool val = i % 3 == 0;
93    array[i] = val;
94    EXPECT_EQ(val, array.at(i));
95  }
96}
97
98// Tests that Array<ScopedMessagePipeHandle> supports transferring handles.
99TEST_F(ArrayTest, Handle) {
100  MessagePipe pipe;
101  Array<ScopedMessagePipeHandle> handles(2);
102  handles[0] = pipe.handle0.Pass();
103  handles[1].reset(pipe.handle1.release());
104
105  EXPECT_FALSE(pipe.handle0.is_valid());
106  EXPECT_FALSE(pipe.handle1.is_valid());
107
108  Array<ScopedMessagePipeHandle> handles2 = handles.Pass();
109  EXPECT_TRUE(handles2[0].is_valid());
110  EXPECT_TRUE(handles2[1].is_valid());
111
112  ScopedMessagePipeHandle pipe_handle = handles2[0].Pass();
113  EXPECT_TRUE(pipe_handle.is_valid());
114  EXPECT_FALSE(handles2[0].is_valid());
115}
116
117// Tests that Array<ScopedMessagePipeHandle> supports closing handles.
118TEST_F(ArrayTest, HandlesAreClosed) {
119  MessagePipe pipe;
120  MojoHandle pipe0_value = pipe.handle0.get().value();
121  MojoHandle pipe1_value = pipe.handle0.get().value();
122
123  {
124    Array<ScopedMessagePipeHandle> handles(2);
125    handles[0] = pipe.handle0.Pass();
126    handles[1].reset(pipe.handle0.release());
127  }
128
129  // We expect the pipes to have been closed.
130  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe0_value));
131  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value));
132}
133
134TEST_F(ArrayTest, Serialization_ArrayOfPOD) {
135  Array<int32_t> array(4);
136  for (size_t i = 0; i < array.size(); ++i)
137    array[i] = static_cast<int32_t>(i);
138
139  size_t size = GetSerializedSize_(array);
140  EXPECT_EQ(8U + 4*4U, size);
141
142  internal::FixedBuffer buf(size);
143  internal::Array_Data<int32_t>* data;
144  SerializeArray_<internal::ArrayValidateParams<0, false,
145                  internal::NoValidateParams> >(
146      array.Pass(), &buf, &data);
147
148  Array<int32_t> array2;
149  Deserialize_(data, &array2);
150
151  EXPECT_EQ(4U, array2.size());
152  for (size_t i = 0; i < array2.size(); ++i)
153    EXPECT_EQ(static_cast<int32_t>(i), array2[i]);
154}
155
156TEST_F(ArrayTest, Serialization_ArrayOfArrayOfPOD) {
157  Array<Array<int32_t> > array(2);
158  for (size_t j = 0; j < array.size(); ++j) {
159    Array<int32_t> inner(4);
160    for (size_t i = 0; i < inner.size(); ++i)
161      inner[i] = static_cast<int32_t>(i + (j * 10));
162    array[j] = inner.Pass();
163  }
164
165  size_t size = GetSerializedSize_(array);
166  EXPECT_EQ(8U + 2*8U + 2*(8U + 4*4U), size);
167
168  internal::FixedBuffer buf(size);
169  internal::Array_Data<internal::Array_Data<int32_t>*>* data;
170  SerializeArray_<internal::ArrayValidateParams<0, false,
171                  internal::ArrayValidateParams<0, false,
172                  internal::NoValidateParams> > >(
173      array.Pass(), &buf, &data);
174
175  Array<Array<int32_t> > array2;
176  Deserialize_(data, &array2);
177
178  EXPECT_EQ(2U, array2.size());
179  for (size_t j = 0; j < array2.size(); ++j) {
180    const Array<int32_t>& inner = array2[j];
181    EXPECT_EQ(4U, inner.size());
182    for (size_t i = 0; i < inner.size(); ++i)
183      EXPECT_EQ(static_cast<int32_t>(i + (j * 10)), inner[i]);
184  }
185}
186
187TEST_F(ArrayTest, Serialization_ArrayOfBool) {
188  Array<bool> array(10);
189  for (size_t i = 0; i < array.size(); ++i)
190    array[i] = i % 2 ? true : false;
191
192  size_t size = GetSerializedSize_(array);
193  EXPECT_EQ(8U + 8U, size);
194
195  internal::FixedBuffer buf(size);
196  internal::Array_Data<bool>* data;
197  SerializeArray_<internal::ArrayValidateParams<0, false,
198                  internal::NoValidateParams> >(
199      array.Pass(), &buf, &data);
200
201  Array<bool> array2;
202  Deserialize_(data, &array2);
203
204  EXPECT_EQ(10U, array2.size());
205  for (size_t i = 0; i < array2.size(); ++i)
206    EXPECT_EQ(i % 2 ? true : false, array2[i]);
207}
208
209TEST_F(ArrayTest, Serialization_ArrayOfString) {
210  Array<String> array(10);
211  for (size_t i = 0; i < array.size(); ++i) {
212    char c = 'A' + static_cast<char>(i);
213    array[i] = String(&c, 1);
214  }
215
216  size_t size = GetSerializedSize_(array);
217  EXPECT_EQ(8U +     // array header
218            10*8U +  // array payload (10 pointers)
219            10*(8U +  // string header
220                8U),  // string length of 1 padded to 8
221            size);
222
223  internal::FixedBuffer buf(size);
224  internal::Array_Data<internal::String_Data*>* data;
225  SerializeArray_<internal::ArrayValidateParams<0, false,
226                  internal::ArrayValidateParams<0, false,
227                  internal::NoValidateParams> > >(
228      array.Pass(), &buf, &data);
229
230  Array<String> array2;
231  Deserialize_(data, &array2);
232
233  EXPECT_EQ(10U, array2.size());
234  for (size_t i = 0; i < array2.size(); ++i) {
235    char c = 'A' + static_cast<char>(i);
236    EXPECT_EQ(String(&c, 1), array2[i]);
237  }
238}
239
240TEST_F(ArrayTest, Resize_Copyable) {
241  ASSERT_EQ(0u, CopyableType::num_instances());
242  mojo::Array<CopyableType> array(3);
243  std::vector<CopyableType*> value_ptrs;
244  value_ptrs.push_back(array[0].ptr());
245  value_ptrs.push_back(array[1].ptr());
246
247  for (size_t i = 0; i < array.size(); i++)
248    array[i].ResetCopied();
249
250  array.resize(2);
251  ASSERT_EQ(2u, array.size());
252  EXPECT_EQ(array.size(), CopyableType::num_instances());
253  for (size_t i = 0; i < array.size(); i++) {
254    EXPECT_FALSE(array[i].copied());
255    EXPECT_EQ(value_ptrs[i], array[i].ptr());
256  }
257
258  array.resize(3);
259  array[2].ResetCopied();
260  ASSERT_EQ(3u, array.size());
261  EXPECT_EQ(array.size(), CopyableType::num_instances());
262  for (size_t i = 0; i < array.size(); i++)
263    EXPECT_FALSE(array[i].copied());
264  value_ptrs.push_back(array[2].ptr());
265
266  size_t capacity = array.storage().capacity();
267  array.resize(capacity);
268  ASSERT_EQ(capacity, array.size());
269  EXPECT_EQ(array.size(), CopyableType::num_instances());
270  for (size_t i = 0; i < 3; i++)
271    EXPECT_FALSE(array[i].copied());
272  for (size_t i = 3; i < array.size(); i++) {
273    array[i].ResetCopied();
274    value_ptrs.push_back(array[i].ptr());
275  }
276
277  array.resize(capacity + 2);
278  ASSERT_EQ(capacity + 2, array.size());
279  EXPECT_EQ(array.size(), CopyableType::num_instances());
280  for (size_t i = 0; i < capacity; i++) {
281    EXPECT_TRUE(array[i].copied());
282    EXPECT_EQ(value_ptrs[i], array[i].ptr());
283  }
284  array.reset();
285  EXPECT_EQ(0u, CopyableType::num_instances());
286  EXPECT_FALSE(array);
287  array.resize(0);
288  EXPECT_EQ(0u, CopyableType::num_instances());
289  EXPECT_TRUE(array);
290}
291
292TEST_F(ArrayTest, Resize_MoveOnly) {
293  ASSERT_EQ(0u, MoveOnlyType::num_instances());
294  mojo::Array<MoveOnlyType> array(3);
295  std::vector<MoveOnlyType*> value_ptrs;
296  value_ptrs.push_back(array[0].ptr());
297  value_ptrs.push_back(array[1].ptr());
298
299  for (size_t i = 0; i < array.size(); i++)
300    EXPECT_FALSE(array[i].moved());
301
302  array.resize(2);
303  ASSERT_EQ(2u, array.size());
304  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
305  for (size_t i = 0; i < array.size(); i++) {
306    EXPECT_FALSE(array[i].moved());
307    EXPECT_EQ(value_ptrs[i], array[i].ptr());
308  }
309
310  array.resize(3);
311  ASSERT_EQ(3u, array.size());
312  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
313  for (size_t i = 0; i < array.size(); i++)
314    EXPECT_FALSE(array[i].moved());
315  value_ptrs.push_back(array[2].ptr());
316
317  size_t capacity = array.storage().capacity();
318  array.resize(capacity);
319  ASSERT_EQ(capacity, array.size());
320  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
321  for (size_t i = 0; i < array.size(); i++)
322    EXPECT_FALSE(array[i].moved());
323  for (size_t i = 3; i < array.size(); i++)
324    value_ptrs.push_back(array[i].ptr());
325
326  array.resize(capacity + 2);
327  ASSERT_EQ(capacity + 2, array.size());
328  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
329  for (size_t i = 0; i < capacity; i++) {
330    EXPECT_TRUE(array[i].moved());
331    EXPECT_EQ(value_ptrs[i], array[i].ptr());
332  }
333  for (size_t i = capacity; i < array.size(); i++)
334    EXPECT_FALSE(array[i].moved());
335
336  array.reset();
337  EXPECT_EQ(0u, MoveOnlyType::num_instances());
338  EXPECT_FALSE(array);
339  array.resize(0);
340  EXPECT_EQ(0u, MoveOnlyType::num_instances());
341  EXPECT_TRUE(array);
342}
343
344TEST_F(ArrayTest, PushBack_Copyable) {
345  ASSERT_EQ(0u, CopyableType::num_instances());
346  mojo::Array<CopyableType> array(2);
347  array.reset();
348  std::vector<CopyableType*> value_ptrs;
349  size_t capacity = array.storage().capacity();
350  for (size_t i = 0; i < capacity; i++) {
351    CopyableType value;
352    value_ptrs.push_back(value.ptr());
353    array.push_back(value);
354    ASSERT_EQ(i + 1, array.size());
355    ASSERT_EQ(i + 1, value_ptrs.size());
356    EXPECT_EQ(array.size() + 1, CopyableType::num_instances());
357    EXPECT_TRUE(array[i].copied());
358    EXPECT_EQ(value_ptrs[i], array[i].ptr());
359    array[i].ResetCopied();
360    EXPECT_TRUE(array);
361  }
362  {
363    CopyableType value;
364    value_ptrs.push_back(value.ptr());
365    array.push_back(value);
366    EXPECT_EQ(array.size() + 1, CopyableType::num_instances());
367  }
368  ASSERT_EQ(capacity + 1, array.size());
369  EXPECT_EQ(array.size(), CopyableType::num_instances());
370
371  for (size_t i = 0; i < array.size(); i++) {
372    EXPECT_TRUE(array[i].copied());
373    EXPECT_EQ(value_ptrs[i], array[i].ptr());
374  }
375  array.reset();
376  EXPECT_EQ(0u, CopyableType::num_instances());
377}
378
379TEST_F(ArrayTest, PushBack_MoveOnly) {
380  ASSERT_EQ(0u, MoveOnlyType::num_instances());
381  mojo::Array<MoveOnlyType> array(2);
382  array.reset();
383  std::vector<MoveOnlyType*> value_ptrs;
384  size_t capacity = array.storage().capacity();
385  for (size_t i = 0; i < capacity; i++) {
386    MoveOnlyType value;
387    value_ptrs.push_back(value.ptr());
388    array.push_back(value.Pass());
389    ASSERT_EQ(i + 1, array.size());
390    ASSERT_EQ(i + 1, value_ptrs.size());
391    EXPECT_EQ(array.size() + 1, MoveOnlyType::num_instances());
392    EXPECT_TRUE(array[i].moved());
393    EXPECT_EQ(value_ptrs[i], array[i].ptr());
394    array[i].ResetMoved();
395    EXPECT_TRUE(array);
396  }
397  {
398    MoveOnlyType value;
399    value_ptrs.push_back(value.ptr());
400    array.push_back(value.Pass());
401    EXPECT_EQ(array.size() + 1, MoveOnlyType::num_instances());
402  }
403  ASSERT_EQ(capacity + 1, array.size());
404  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
405
406  for (size_t i = 0; i < array.size(); i++) {
407    EXPECT_TRUE(array[i].moved());
408    EXPECT_EQ(value_ptrs[i], array[i].ptr());
409  }
410  array.reset();
411  EXPECT_EQ(0u, MoveOnlyType::num_instances());
412}
413
414}  // namespace
415}  // namespace test
416}  // namespace mojo
417