C++程序  |  405行  |  13.24 KB

// 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.

#include <stddef.h>
#include <stdint.h>
#include <utility>

#include "mojo/public/cpp/bindings/lib/array_internal.h"
#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
#include "mojo/public/cpp/bindings/tests/container_test_util.h"
#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace test {

// Common tests for both mojo::Array and mojo::WTFArray.
template <template <typename...> class ArrayType>
class ArrayCommonTest {
 public:
  // Tests null and empty arrays.
  static void NullAndEmpty() {
    ArrayType<char> array0;
    EXPECT_TRUE(array0.empty());
    EXPECT_FALSE(array0.is_null());
    array0 = nullptr;
    EXPECT_TRUE(array0.is_null());
    EXPECT_FALSE(array0.empty());

    ArrayType<char> array1(nullptr);
    EXPECT_TRUE(array1.is_null());
    EXPECT_FALSE(array1.empty());
    array1.SetToEmpty();
    EXPECT_TRUE(array1.empty());
    EXPECT_FALSE(array1.is_null());
  }

  // Tests that basic array operations work.
  static void Basic() {
    ArrayType<char> array(8);
    for (size_t i = 0; i < array.size(); ++i) {
      char val = static_cast<char>(i * 2);
      array[i] = val;
      EXPECT_EQ(val, array.at(i));
    }
  }

  // Tests that basic ArrayType<bool> operations work.
  static void Bool() {
    ArrayType<bool> array(64);
    for (size_t i = 0; i < array.size(); ++i) {
      bool val = i % 3 == 0;
      array[i] = val;
      EXPECT_EQ(val, array.at(i));
    }
  }

  // Tests that ArrayType<ScopedMessagePipeHandle> supports transferring
  // handles.
  static void Handle() {
    MessagePipe pipe;
    ArrayType<ScopedMessagePipeHandle> handles(2);
    handles[0] = std::move(pipe.handle0);
    handles[1].reset(pipe.handle1.release());

    EXPECT_FALSE(pipe.handle0.is_valid());
    EXPECT_FALSE(pipe.handle1.is_valid());

    ArrayType<ScopedMessagePipeHandle> handles2 = std::move(handles);
    EXPECT_TRUE(handles2[0].is_valid());
    EXPECT_TRUE(handles2[1].is_valid());

    ScopedMessagePipeHandle pipe_handle = std::move(handles2[0]);
    EXPECT_TRUE(pipe_handle.is_valid());
    EXPECT_FALSE(handles2[0].is_valid());
  }

  // Tests that ArrayType<ScopedMessagePipeHandle> supports closing handles.
  static void HandlesAreClosed() {
    MessagePipe pipe;
    MojoHandle pipe0_value = pipe.handle0.get().value();
    MojoHandle pipe1_value = pipe.handle0.get().value();

    {
      ArrayType<ScopedMessagePipeHandle> handles(2);
      handles[0] = std::move(pipe.handle0);
      handles[1].reset(pipe.handle0.release());
    }

    // We expect the pipes to have been closed.
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe0_value));
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value));
  }

  static void Clone() {
    {
      // Test POD.
      ArrayType<int32_t> array(3);
      for (size_t i = 0; i < array.size(); ++i)
        array[i] = static_cast<int32_t>(i);

      ArrayType<int32_t> clone_array = array.Clone();
      EXPECT_EQ(array.size(), clone_array.size());
      for (size_t i = 0; i < array.size(); ++i)
        EXPECT_EQ(array[i], clone_array[i]);
    }

    {
      // Test copyable object.
      ArrayType<String> array(2);
      array[0] = "hello";
      array[1] = "world";

      ArrayType<String> clone_array = array.Clone();
      EXPECT_EQ(array.size(), clone_array.size());
      for (size_t i = 0; i < array.size(); ++i)
        EXPECT_EQ(array[i], clone_array[i]);
    }

    {
      // Test struct.
      ArrayType<RectPtr> array(2);
      array[1] = Rect::New();
      array[1]->x = 1;
      array[1]->y = 2;
      array[1]->width = 3;
      array[1]->height = 4;

      ArrayType<RectPtr> clone_array = array.Clone();
      EXPECT_EQ(array.size(), clone_array.size());
      EXPECT_TRUE(clone_array[0].is_null());
      EXPECT_EQ(array[1]->x, clone_array[1]->x);
      EXPECT_EQ(array[1]->y, clone_array[1]->y);
      EXPECT_EQ(array[1]->width, clone_array[1]->width);
      EXPECT_EQ(array[1]->height, clone_array[1]->height);
    }

    {
      // Test array of array.
      ArrayType<ArrayType<int8_t>> array(2);
      array[0] = nullptr;
      array[1] = ArrayType<int8_t>(2);
      array[1][0] = 0;
      array[1][1] = 1;

      ArrayType<ArrayType<int8_t>> clone_array = array.Clone();
      EXPECT_EQ(array.size(), clone_array.size());
      EXPECT_TRUE(clone_array[0].is_null());
      EXPECT_EQ(array[1].size(), clone_array[1].size());
      EXPECT_EQ(array[1][0], clone_array[1][0]);
      EXPECT_EQ(array[1][1], clone_array[1][1]);
    }

    {
      // Test that array of handles still works although Clone() is not
      // available.
      ArrayType<ScopedMessagePipeHandle> array(10);
      EXPECT_FALSE(array[0].is_valid());
    }
  }

  static void Serialization_ArrayOfPOD() {
    ArrayType<int32_t> array(4);
    for (size_t i = 0; i < array.size(); ++i)
      array[i] = static_cast<int32_t>(i);

    size_t size =
        mojo::internal::PrepareToSerialize<Array<int32_t>>(array, nullptr);
    EXPECT_EQ(8U + 4 * 4U, size);

    mojo::internal::FixedBufferForTesting buf(size);
    mojo::internal::Array_Data<int32_t>* data;
    mojo::internal::ContainerValidateParams validate_params(0, false, nullptr);
    mojo::internal::Serialize<Array<int32_t>>(array, &buf, &data,
                                              &validate_params, nullptr);

    ArrayType<int32_t> array2;
    mojo::internal::Deserialize<Array<int32_t>>(data, &array2, nullptr);

    EXPECT_EQ(4U, array2.size());
    for (size_t i = 0; i < array2.size(); ++i)
      EXPECT_EQ(static_cast<int32_t>(i), array2[i]);
  }

  static void Serialization_EmptyArrayOfPOD() {
    ArrayType<int32_t> array;
    size_t size =
        mojo::internal::PrepareToSerialize<Array<int32_t>>(array, nullptr);
    EXPECT_EQ(8U, size);

    mojo::internal::FixedBufferForTesting buf(size);
    mojo::internal::Array_Data<int32_t>* data;
    mojo::internal::ContainerValidateParams validate_params(0, false, nullptr);
    mojo::internal::Serialize<Array<int32_t>>(array, &buf, &data,
                                              &validate_params, nullptr);

    ArrayType<int32_t> array2;
    mojo::internal::Deserialize<Array<int32_t>>(data, &array2, nullptr);
    EXPECT_EQ(0U, array2.size());
  }

  static void Serialization_ArrayOfArrayOfPOD() {
    ArrayType<ArrayType<int32_t>> array(2);
    for (size_t j = 0; j < array.size(); ++j) {
      ArrayType<int32_t> inner(4);
      for (size_t i = 0; i < inner.size(); ++i)
        inner[i] = static_cast<int32_t>(i + (j * 10));
      array[j] = std::move(inner);
    }

    size_t size = mojo::internal::PrepareToSerialize<Array<Array<int32_t>>>(
        array, nullptr);
    EXPECT_EQ(8U + 2 * 8U + 2 * (8U + 4 * 4U), size);

    mojo::internal::FixedBufferForTesting buf(size);
    typename mojo::internal::MojomTypeTraits<Array<Array<int32_t>>>::Data* data;
    mojo::internal::ContainerValidateParams validate_params(
        0, false,
        new mojo::internal::ContainerValidateParams(0, false, nullptr));
    mojo::internal::Serialize<Array<Array<int32_t>>>(array, &buf, &data,
                                                     &validate_params, nullptr);

    ArrayType<ArrayType<int32_t>> array2;
    mojo::internal::Deserialize<Array<Array<int32_t>>>(data, &array2, nullptr);

    EXPECT_EQ(2U, array2.size());
    for (size_t j = 0; j < array2.size(); ++j) {
      const ArrayType<int32_t>& inner = array2[j];
      EXPECT_EQ(4U, inner.size());
      for (size_t i = 0; i < inner.size(); ++i)
        EXPECT_EQ(static_cast<int32_t>(i + (j * 10)), inner[i]);
    }
  }

  static void Serialization_ArrayOfBool() {
    ArrayType<bool> array(10);
    for (size_t i = 0; i < array.size(); ++i)
      array[i] = i % 2 ? true : false;

    size_t size =
        mojo::internal::PrepareToSerialize<Array<bool>>(array, nullptr);
    EXPECT_EQ(8U + 8U, size);

    mojo::internal::FixedBufferForTesting buf(size);
    mojo::internal::Array_Data<bool>* data;
    mojo::internal::ContainerValidateParams validate_params(0, false, nullptr);
    mojo::internal::Serialize<Array<bool>>(array, &buf, &data, &validate_params,
                                           nullptr);

    ArrayType<bool> array2;
    mojo::internal::Deserialize<Array<bool>>(data, &array2, nullptr);

    EXPECT_EQ(10U, array2.size());
    for (size_t i = 0; i < array2.size(); ++i)
      EXPECT_EQ(i % 2 ? true : false, array2[i]);
  }

  static void Serialization_ArrayOfString() {
    ArrayType<String> array(10);
    for (size_t i = 0; i < array.size(); ++i) {
      char c = 'A' + static_cast<char>(i);
      array[i] = String(&c, 1);
    }

    size_t size =
        mojo::internal::PrepareToSerialize<Array<String>>(array, nullptr);
    EXPECT_EQ(8U +            // array header
                  10 * 8U +   // array payload (10 pointers)
                  10 * (8U +  // string header
                        8U),  // string length of 1 padded to 8
              size);

    mojo::internal::FixedBufferForTesting buf(size);
    typename mojo::internal::MojomTypeTraits<Array<String>>::Data* data;
    mojo::internal::ContainerValidateParams validate_params(
        0, false,
        new mojo::internal::ContainerValidateParams(0, false, nullptr));
    mojo::internal::Serialize<Array<String>>(array, &buf, &data,
                                             &validate_params, nullptr);

    ArrayType<String> array2;
    mojo::internal::Deserialize<Array<String>>(data, &array2, nullptr);

    EXPECT_EQ(10U, array2.size());
    for (size_t i = 0; i < array2.size(); ++i) {
      char c = 'A' + static_cast<char>(i);
      EXPECT_EQ(String(&c, 1), array2[i]);
    }
  }

  static void Resize_Copyable() {
    ASSERT_EQ(0u, CopyableType::num_instances());
    ArrayType<CopyableType> array(3);
    std::vector<CopyableType*> value_ptrs;
    value_ptrs.push_back(array[0].ptr());
    value_ptrs.push_back(array[1].ptr());

    for (size_t i = 0; i < array.size(); i++)
      array[i].ResetCopied();

    array.resize(2);
    ASSERT_EQ(2u, array.size());
    EXPECT_EQ(array.size(), CopyableType::num_instances());
    for (size_t i = 0; i < array.size(); i++) {
      EXPECT_FALSE(array[i].copied());
      EXPECT_EQ(value_ptrs[i], array[i].ptr());
    }

    array.resize(3);
    array[2].ResetCopied();
    ASSERT_EQ(3u, array.size());
    EXPECT_EQ(array.size(), CopyableType::num_instances());
    for (size_t i = 0; i < array.size(); i++)
      EXPECT_FALSE(array[i].copied());
    value_ptrs.push_back(array[2].ptr());

    size_t capacity = array.storage().capacity();
    array.resize(capacity);
    ASSERT_EQ(capacity, array.size());
    EXPECT_EQ(array.size(), CopyableType::num_instances());
    for (size_t i = 0; i < 3; i++)
      EXPECT_FALSE(array[i].copied());
    for (size_t i = 3; i < array.size(); i++) {
      array[i].ResetCopied();
      value_ptrs.push_back(array[i].ptr());
    }

    array.resize(capacity + 2);
    ASSERT_EQ(capacity + 2, array.size());
    EXPECT_EQ(array.size(), CopyableType::num_instances());
    for (size_t i = 0; i < capacity; i++) {
      EXPECT_TRUE(array[i].copied());
      EXPECT_EQ(value_ptrs[i], array[i].ptr());
    }
    array = nullptr;
    EXPECT_EQ(0u, CopyableType::num_instances());
    EXPECT_FALSE(array);
    array.resize(0);
    EXPECT_EQ(0u, CopyableType::num_instances());
    EXPECT_TRUE(array);
  }

  static void Resize_MoveOnly() {
    ASSERT_EQ(0u, MoveOnlyType::num_instances());
    ArrayType<MoveOnlyType> array(3);
    std::vector<MoveOnlyType*> value_ptrs;
    value_ptrs.push_back(array[0].ptr());
    value_ptrs.push_back(array[1].ptr());

    for (size_t i = 0; i < array.size(); i++)
      EXPECT_FALSE(array[i].moved());

    array.resize(2);
    ASSERT_EQ(2u, array.size());
    EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
    for (size_t i = 0; i < array.size(); i++) {
      EXPECT_FALSE(array[i].moved());
      EXPECT_EQ(value_ptrs[i], array[i].ptr());
    }

    array.resize(3);
    ASSERT_EQ(3u, array.size());
    EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
    for (size_t i = 0; i < array.size(); i++)
      EXPECT_FALSE(array[i].moved());
    value_ptrs.push_back(array[2].ptr());

    size_t capacity = array.storage().capacity();
    array.resize(capacity);
    ASSERT_EQ(capacity, array.size());
    EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
    for (size_t i = 0; i < array.size(); i++)
      EXPECT_FALSE(array[i].moved());
    for (size_t i = 3; i < array.size(); i++)
      value_ptrs.push_back(array[i].ptr());

    array.resize(capacity + 2);
    ASSERT_EQ(capacity + 2, array.size());
    EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
    for (size_t i = 0; i < capacity; i++) {
      EXPECT_TRUE(array[i].moved());
      EXPECT_EQ(value_ptrs[i], array[i].ptr());
    }
    for (size_t i = capacity; i < array.size(); i++)
      EXPECT_FALSE(array[i].moved());

    array = nullptr;
    EXPECT_EQ(0u, MoveOnlyType::num_instances());
    EXPECT_FALSE(array);
    array.resize(0);
    EXPECT_EQ(0u, MoveOnlyType::num_instances());
    EXPECT_TRUE(array);
  }
};

#define ARRAY_COMMON_TEST(ArrayType, test_name) \
  TEST_F(ArrayType##Test, test_name) {          \
    ArrayCommonTest<ArrayType>::test_name();    \
  }

}  // namespace test
}  // namespace mojo