diff options
author | Hidehiko Abe <hidehiko@google.com> | 2018-04-17 16:34:13 +0900 |
---|---|---|
committer | Hidehiko Abe <hidehiko@google.com> | 2018-04-17 16:56:42 +0900 |
commit | 1e4a1e50aed7593adac78af6f319adb67f03d7bb (patch) | |
tree | 1398145f7694eac739142d9bcbfcdf3d8cf4b9a8 /mojo/public/cpp/bindings | |
parent | 0325b56b0518f5ca16701e5048fcf81cc96fd725 (diff) | |
download | libmojo-1e4a1e50aed7593adac78af6f319adb67f03d7bb.tar.gz |
Reduce diffs from Chrome r456626.
Currently, mojo/ directory is more diverged than it should be.
This CL fills the unnecessary gaps.
Bug: 73606903
Test: Built locally. Treehugger. Made sure the diff on eyes.
Change-Id: I65877b0ff853ecfd6661259f97b0078631a158a7
Diffstat (limited to 'mojo/public/cpp/bindings')
68 files changed, 4080 insertions, 2736 deletions
diff --git a/mojo/public/cpp/bindings/associated_binding_set.h b/mojo/public/cpp/bindings/associated_binding_set.h new file mode 100644 index 0000000..59600c6 --- /dev/null +++ b/mojo/public/cpp/bindings/associated_binding_set.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_SET_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_SET_H_ + +#include "mojo/public/cpp/bindings/associated_binding.h" +#include "mojo/public/cpp/bindings/associated_interface_ptr.h" +#include "mojo/public/cpp/bindings/associated_interface_request.h" +#include "mojo/public/cpp/bindings/binding_set.h" + +namespace mojo { + +template <typename Interface, typename ImplRefTraits> +struct BindingSetTraits<AssociatedBinding<Interface, ImplRefTraits>> { + using ProxyType = AssociatedInterfacePtr<Interface>; + using RequestType = AssociatedInterfaceRequest<Interface>; + using BindingType = AssociatedBinding<Interface, ImplRefTraits>; + using ImplPointerType = typename BindingType::ImplPointerType; +}; + +template <typename Interface, typename ContextType = void> +using AssociatedBindingSet = + BindingSetBase<Interface, AssociatedBinding<Interface>, ContextType>; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_SET_H_ diff --git a/mojo/public/cpp/bindings/lib/associated_binding.cc b/mojo/public/cpp/bindings/lib/associated_binding.cc new file mode 100644 index 0000000..6788e68 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/associated_binding.cc @@ -0,0 +1,62 @@ +// Copyright 2017 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 "mojo/public/cpp/bindings/associated_binding.h" + +namespace mojo { + +AssociatedBindingBase::AssociatedBindingBase() {} + +AssociatedBindingBase::~AssociatedBindingBase() {} + +void AssociatedBindingBase::AddFilter(std::unique_ptr<MessageReceiver> filter) { + DCHECK(endpoint_client_); + endpoint_client_->AddFilter(std::move(filter)); +} + +void AssociatedBindingBase::Close() { + endpoint_client_.reset(); +} + +void AssociatedBindingBase::CloseWithReason(uint32_t custom_reason, + const std::string& description) { + if (endpoint_client_) + endpoint_client_->CloseWithReason(custom_reason, description); + Close(); +} + +void AssociatedBindingBase::set_connection_error_handler( + const base::Closure& error_handler) { + DCHECK(is_bound()); + endpoint_client_->set_connection_error_handler(error_handler); +} + +void AssociatedBindingBase::set_connection_error_with_reason_handler( + const ConnectionErrorWithReasonCallback& error_handler) { + DCHECK(is_bound()); + endpoint_client_->set_connection_error_with_reason_handler(error_handler); +} + +void AssociatedBindingBase::FlushForTesting() { + endpoint_client_->FlushForTesting(); +} + +void AssociatedBindingBase::BindImpl( + ScopedInterfaceEndpointHandle handle, + MessageReceiverWithResponderStatus* receiver, + std::unique_ptr<MessageReceiver> payload_validator, + bool expect_sync_requests, + scoped_refptr<base::SingleThreadTaskRunner> runner, + uint32_t interface_version) { + if (!handle.is_valid()) { + endpoint_client_.reset(); + return; + } + + endpoint_client_.reset(new InterfaceEndpointClient( + std::move(handle), receiver, std::move(payload_validator), + expect_sync_requests, std::move(runner), interface_version)); +} + +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/wtf_hash_util.h b/mojo/public/cpp/bindings/lib/wtf_hash_util.h new file mode 100644 index 0000000..cc590da --- /dev/null +++ b/mojo/public/cpp/bindings/lib/wtf_hash_util.h @@ -0,0 +1,132 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_HASH_UTIL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_HASH_UTIL_H_ + +#include <type_traits> + +#include "mojo/public/cpp/bindings/lib/hash_util.h" +#include "mojo/public/cpp/bindings/struct_ptr.h" +#include "third_party/WebKit/Source/wtf/HashFunctions.h" +#include "third_party/WebKit/Source/wtf/text/StringHash.h" +#include "third_party/WebKit/Source/wtf/text/WTFString.h" + +namespace mojo { +namespace internal { + +template <typename T> +size_t WTFHashCombine(size_t seed, const T& value) { + // Based on proposal in: + // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf + // + // TODO(tibell): We'd like to use WTF::DefaultHash instead of std::hash, but + // there is no general template specialization of DefaultHash for enums + // and there can't be an instance for bool. + return seed ^ (std::hash<T>()(value) + (seed << 6) + (seed >> 2)); +} + +template <typename T, bool has_hash_method = HasHashMethod<T>::value> +struct WTFHashTraits; + +template <typename T> +size_t WTFHash(size_t seed, const T& value); + +template <typename T> +struct WTFHashTraits<T, true> { + static size_t Hash(size_t seed, const T& value) { return value.Hash(seed); } +}; + +template <typename T> +struct WTFHashTraits<T, false> { + static size_t Hash(size_t seed, const T& value) { + return WTFHashCombine(seed, value); + } +}; + +template <> +struct WTFHashTraits<WTF::String, false> { + static size_t Hash(size_t seed, const WTF::String& value) { + return HashCombine(seed, WTF::StringHash::hash(value)); + } +}; + +template <typename T> +size_t WTFHash(size_t seed, const T& value) { + return WTFHashTraits<T>::Hash(seed, value); +} + +template <typename T> +struct StructPtrHashFn { + static unsigned hash(const StructPtr<T>& value) { + return value.Hash(kHashSeed); + } + static bool equal(const StructPtr<T>& left, const StructPtr<T>& right) { + return left.Equals(right); + } + static const bool safeToCompareToEmptyOrDeleted = false; +}; + +template <typename T> +struct InlinedStructPtrHashFn { + static unsigned hash(const InlinedStructPtr<T>& value) { + return value.Hash(kHashSeed); + } + static bool equal(const InlinedStructPtr<T>& left, + const InlinedStructPtr<T>& right) { + return left.Equals(right); + } + static const bool safeToCompareToEmptyOrDeleted = false; +}; + +} // namespace internal +} // namespace mojo + +namespace WTF { + +template <typename T> +struct DefaultHash<mojo::StructPtr<T>> { + using Hash = mojo::internal::StructPtrHashFn<T>; +}; + +template <typename T> +struct HashTraits<mojo::StructPtr<T>> + : public GenericHashTraits<mojo::StructPtr<T>> { + static const bool hasIsEmptyValueFunction = true; + static bool isEmptyValue(const mojo::StructPtr<T>& value) { + return value.is_null(); + } + static void constructDeletedValue(mojo::StructPtr<T>& slot, bool) { + mojo::internal::StructPtrWTFHelper<T>::ConstructDeletedValue(slot); + } + static bool isDeletedValue(const mojo::StructPtr<T>& value) { + return mojo::internal::StructPtrWTFHelper<T>::IsHashTableDeletedValue( + value); + } +}; + +template <typename T> +struct DefaultHash<mojo::InlinedStructPtr<T>> { + using Hash = mojo::internal::InlinedStructPtrHashFn<T>; +}; + +template <typename T> +struct HashTraits<mojo::InlinedStructPtr<T>> + : public GenericHashTraits<mojo::InlinedStructPtr<T>> { + static const bool hasIsEmptyValueFunction = true; + static bool isEmptyValue(const mojo::InlinedStructPtr<T>& value) { + return value.is_null(); + } + static void constructDeletedValue(mojo::InlinedStructPtr<T>& slot, bool) { + mojo::internal::InlinedStructPtrWTFHelper<T>::ConstructDeletedValue(slot); + } + static bool isDeletedValue(const mojo::InlinedStructPtr<T>& value) { + return mojo::internal::InlinedStructPtrWTFHelper< + T>::IsHashTableDeletedValue(value); + } +}; + +} // namespace WTF + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_HASH_UTIL_H_ diff --git a/mojo/public/cpp/bindings/strong_associated_binding.h b/mojo/public/cpp/bindings/strong_associated_binding.h new file mode 100644 index 0000000..a1e299b --- /dev/null +++ b/mojo/public/cpp/bindings/strong_associated_binding.h @@ -0,0 +1,125 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_ + +#include <memory> +#include <string> +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "mojo/public/cpp/bindings/associated_binding.h" +#include "mojo/public/cpp/bindings/associated_interface_request.h" +#include "mojo/public/cpp/bindings/connection_error_callback.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +template <typename Interface> +class StrongAssociatedBinding; + +template <typename Interface> +using StrongAssociatedBindingPtr = + base::WeakPtr<StrongAssociatedBinding<Interface>>; + +// This connects an interface implementation strongly to an associated pipe. +// When a connection error is detected the implementation is deleted. If the +// task runner that a StrongAssociatedBinding is bound on is stopped, the +// connection error handler will not be invoked and the implementation will not +// be deleted. +// +// To use, call StrongAssociatedBinding<T>::Create() (see below) or the helper +// MakeStrongAssociatedBinding function: +// +// mojo::MakeStrongAssociatedBinding(base::MakeUnique<FooImpl>(), +// std::move(foo_request)); +// +template <typename Interface> +class StrongAssociatedBinding { + public: + // Create a new StrongAssociatedBinding instance. The instance owns itself, + // cleaning up only in the event of a pipe connection error. Returns a WeakPtr + // to the new StrongAssociatedBinding instance. + static StrongAssociatedBindingPtr<Interface> Create( + std::unique_ptr<Interface> impl, + AssociatedInterfaceRequest<Interface> request) { + StrongAssociatedBinding* binding = + new StrongAssociatedBinding(std::move(impl), std::move(request)); + return binding->weak_factory_.GetWeakPtr(); + } + + // Note: The error handler must not delete the interface implementation. + // + // This method may only be called after this StrongAssociatedBinding has been + // bound to a message pipe. + void set_connection_error_handler(const base::Closure& error_handler) { + DCHECK(binding_.is_bound()); + connection_error_handler_ = error_handler; + connection_error_with_reason_handler_.Reset(); + } + + void set_connection_error_with_reason_handler( + const ConnectionErrorWithReasonCallback& error_handler) { + DCHECK(binding_.is_bound()); + connection_error_with_reason_handler_ = error_handler; + connection_error_handler_.Reset(); + } + + // Forces the binding to close. This destroys the StrongBinding instance. + void Close() { delete this; } + + Interface* impl() { return impl_.get(); } + + // Sends a message on the underlying message pipe and runs the current + // message loop until its response is received. This can be used in tests to + // verify that no message was sent on a message pipe in response to some + // stimulus. + void FlushForTesting() { binding_.FlushForTesting(); } + + private: + StrongAssociatedBinding(std::unique_ptr<Interface> impl, + AssociatedInterfaceRequest<Interface> request) + : impl_(std::move(impl)), + binding_(impl_.get(), std::move(request)), + weak_factory_(this) { + binding_.set_connection_error_with_reason_handler(base::Bind( + &StrongAssociatedBinding::OnConnectionError, base::Unretained(this))); + } + + ~StrongAssociatedBinding() {} + + void OnConnectionError(uint32_t custom_reason, + const std::string& description) { + if (!connection_error_handler_.is_null()) + connection_error_handler_.Run(); + else if (!connection_error_with_reason_handler_.is_null()) + connection_error_with_reason_handler_.Run(custom_reason, description); + Close(); + } + + std::unique_ptr<Interface> impl_; + base::Closure connection_error_handler_; + ConnectionErrorWithReasonCallback connection_error_with_reason_handler_; + AssociatedBinding<Interface> binding_; + base::WeakPtrFactory<StrongAssociatedBinding> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(StrongAssociatedBinding); +}; + +template <typename Interface, typename Impl> +StrongAssociatedBindingPtr<Interface> MakeStrongAssociatedBinding( + std::unique_ptr<Impl> impl, + AssociatedInterfaceRequest<Interface> request) { + return StrongAssociatedBinding<Interface>::Create(std::move(impl), + std::move(request)); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_ diff --git a/mojo/public/cpp/bindings/strong_binding_set.h b/mojo/public/cpp/bindings/strong_binding_set.h new file mode 100644 index 0000000..f6bcd52 --- /dev/null +++ b/mojo/public/cpp/bindings/strong_binding_set.h @@ -0,0 +1,26 @@ +// Copyright 2017 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_SET_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_SET_H_ + +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/unique_ptr_impl_ref_traits.h" + +namespace mojo { + +// This class manages a set of bindings. When the pipe a binding is bound to is +// disconnected, the binding is automatically destroyed and removed from the +// set, and the interface implementation is deleted. When the StrongBindingSet +// is destructed, all outstanding bindings in the set are destroyed and all the +// bound interface implementations are automatically deleted. +template <typename Interface, typename ContextType = void> +using StrongBindingSet = + BindingSetBase<Interface, + Binding<Interface, UniquePtrImplRefTraits<Interface>>, + ContextType>; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_SET_H_ diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn index 4e38f15..6244226 100644 --- a/mojo/public/cpp/bindings/tests/BUILD.gn +++ b/mojo/public/cpp/bindings/tests/BUILD.gn @@ -2,39 +2,35 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("../../../mojo_application.gni") - source_set("tests") { testonly = true sources = [ - "array_common_test.h", - "array_unittest.cc", "associated_interface_unittest.cc", "bind_task_runner_unittest.cc", "binding_callback_unittest.cc", + "binding_set_unittest.cc", "binding_unittest.cc", "buffer_unittest.cc", "connector_unittest.cc", "constant_unittest.cc", "container_test_util.cc", "container_test_util.h", + "data_view_unittest.cc", "equals_unittest.cc", "handle_passing_unittest.cc", + "hash_unittest.cc", "interface_ptr_unittest.cc", - "map_common_test.h", "map_unittest.cc", "message_queue.cc", "message_queue.h", "multiplex_router_unittest.cc", + "report_bad_message_unittest.cc", "request_response_unittest.cc", "router_test_util.cc", "router_test_util.h", - "router_unittest.cc", "sample_service_unittest.cc", "serialization_warning_unittest.cc", - "stl_converters_unittest.cc", - "string_unittest.cc", "struct_unittest.cc", "sync_method_unittest.cc", "type_conversion_unittest.cc", @@ -46,10 +42,14 @@ source_set("tests") { deps = [ ":mojo_public_bindings_test_utils", + "//base/test:test_support", + "//mojo/edk/system", "//mojo/public/cpp/bindings", "//mojo/public/cpp/system", "//mojo/public/cpp/test_support:test_utils", "//mojo/public/interfaces/bindings/tests:test_associated_interfaces", + "//mojo/public/interfaces/bindings/tests:test_export_component", + "//mojo/public/interfaces/bindings/tests:test_exported_import", "//mojo/public/interfaces/bindings/tests:test_interfaces", "//mojo/public/interfaces/bindings/tests:test_interfaces_experimental", "//mojo/public/interfaces/bindings/tests:test_struct_traits_interfaces", @@ -77,12 +77,10 @@ if (!is_ios) { testonly = true sources = [ - "array_common_test.h", "container_test_util.cc", "container_test_util.h", - "map_common_test.h", "variant_test_util.h", - "wtf_array_unittest.cc", + "wtf_hash_unittest.cc", "wtf_map_unittest.cc", "wtf_types_unittest.cc", ] @@ -90,7 +88,10 @@ if (!is_ios) { deps = [ "//mojo/public/cpp/bindings", "//mojo/public/cpp/system", + "//mojo/public/interfaces/bindings/tests:test_export_blink_component", + "//mojo/public/interfaces/bindings/tests:test_exported_import_blink", "//mojo/public/interfaces/bindings/tests:test_interfaces", + "//mojo/public/interfaces/bindings/tests:test_interfaces_blink", "//mojo/public/interfaces/bindings/tests:test_wtf_types", "//mojo/public/interfaces/bindings/tests:test_wtf_types_blink", "//testing/gtest", @@ -123,6 +124,7 @@ source_set("perftests") { deps = [ "//base/test:test_support", + "//mojo/edk/system", "//mojo/edk/test:test_support", "//mojo/public/cpp/bindings", "//mojo/public/cpp/system", diff --git a/mojo/public/cpp/bindings/tests/array_common_test.h b/mojo/public/cpp/bindings/tests/array_common_test.h deleted file mode 100644 index 6b4bcfb..0000000 --- a/mojo/public/cpp/bindings/tests/array_common_test.h +++ /dev/null @@ -1,404 +0,0 @@ -// 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 diff --git a/mojo/public/cpp/bindings/tests/array_unittest.cc b/mojo/public/cpp/bindings/tests/array_unittest.cc deleted file mode 100644 index 0700bb1..0000000 --- a/mojo/public/cpp/bindings/tests/array_unittest.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2014 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 "mojo/public/cpp/bindings/array.h" - -#include "mojo/public/cpp/bindings/lib/serialization.h" -#include "mojo/public/cpp/bindings/tests/array_common_test.h" -#include "mojo/public/cpp/bindings/tests/container_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace test { -namespace { - -using ArrayTest = testing::Test; - -ARRAY_COMMON_TEST(Array, NullAndEmpty) -ARRAY_COMMON_TEST(Array, Basic) -ARRAY_COMMON_TEST(Array, Bool) -ARRAY_COMMON_TEST(Array, Handle) -ARRAY_COMMON_TEST(Array, HandlesAreClosed) -ARRAY_COMMON_TEST(Array, Clone) -ARRAY_COMMON_TEST(Array, Serialization_ArrayOfPOD) -ARRAY_COMMON_TEST(Array, Serialization_EmptyArrayOfPOD) -ARRAY_COMMON_TEST(Array, Serialization_ArrayOfArrayOfPOD) -ARRAY_COMMON_TEST(Array, Serialization_ArrayOfBool) -ARRAY_COMMON_TEST(Array, Serialization_ArrayOfString) -ARRAY_COMMON_TEST(Array, Resize_Copyable) -ARRAY_COMMON_TEST(Array, Resize_MoveOnly) - -TEST_F(ArrayTest, PushBack_Copyable) { - ASSERT_EQ(0u, CopyableType::num_instances()); - Array<CopyableType> array(2); - array = nullptr; - std::vector<CopyableType*> value_ptrs; - size_t capacity = array.storage().capacity(); - for (size_t i = 0; i < capacity; i++) { - CopyableType value; - value_ptrs.push_back(value.ptr()); - array.push_back(value); - ASSERT_EQ(i + 1, array.size()); - ASSERT_EQ(i + 1, value_ptrs.size()); - EXPECT_EQ(array.size() + 1, CopyableType::num_instances()); - EXPECT_TRUE(array[i].copied()); - EXPECT_EQ(value_ptrs[i], array[i].ptr()); - array[i].ResetCopied(); - EXPECT_TRUE(array); - } - { - CopyableType value; - value_ptrs.push_back(value.ptr()); - array.push_back(value); - EXPECT_EQ(array.size() + 1, CopyableType::num_instances()); - } - ASSERT_EQ(capacity + 1, array.size()); - EXPECT_EQ(array.size(), CopyableType::num_instances()); - - for (size_t i = 0; i < array.size(); i++) { - EXPECT_TRUE(array[i].copied()); - EXPECT_EQ(value_ptrs[i], array[i].ptr()); - } - array = nullptr; - EXPECT_EQ(0u, CopyableType::num_instances()); -} - -TEST_F(ArrayTest, PushBack_MoveOnly) { - ASSERT_EQ(0u, MoveOnlyType::num_instances()); - Array<MoveOnlyType> array(2); - array = nullptr; - std::vector<MoveOnlyType*> value_ptrs; - size_t capacity = array.storage().capacity(); - for (size_t i = 0; i < capacity; i++) { - MoveOnlyType value; - value_ptrs.push_back(value.ptr()); - array.push_back(std::move(value)); - ASSERT_EQ(i + 1, array.size()); - ASSERT_EQ(i + 1, value_ptrs.size()); - EXPECT_EQ(array.size() + 1, MoveOnlyType::num_instances()); - EXPECT_TRUE(array[i].moved()); - EXPECT_EQ(value_ptrs[i], array[i].ptr()); - array[i].ResetMoved(); - EXPECT_TRUE(array); - } - { - MoveOnlyType value; - value_ptrs.push_back(value.ptr()); - array.push_back(std::move(value)); - EXPECT_EQ(array.size() + 1, MoveOnlyType::num_instances()); - } - ASSERT_EQ(capacity + 1, array.size()); - EXPECT_EQ(array.size(), MoveOnlyType::num_instances()); - - for (size_t i = 0; i < array.size(); i++) { - EXPECT_TRUE(array[i].moved()); - EXPECT_EQ(value_ptrs[i], array[i].ptr()); - } - array = nullptr; - EXPECT_EQ(0u, MoveOnlyType::num_instances()); -} - -TEST_F(ArrayTest, MoveFromAndToSTLVector_Copyable) { - std::vector<CopyableType> vec1(1); - Array<CopyableType> arr(std::move(vec1)); - ASSERT_EQ(1u, arr.size()); - ASSERT_FALSE(arr[0].copied()); - - std::vector<CopyableType> vec2(arr.PassStorage()); - ASSERT_EQ(1u, vec2.size()); - ASSERT_FALSE(vec2[0].copied()); - - ASSERT_EQ(0u, arr.size()); - ASSERT_TRUE(arr.is_null()); -} - -TEST_F(ArrayTest, MoveFromAndToSTLVector_MoveOnly) { - std::vector<MoveOnlyType> vec1(1); - Array<MoveOnlyType> arr(std::move(vec1)); - - ASSERT_EQ(1u, arr.size()); - - std::vector<MoveOnlyType> vec2(arr.PassStorage()); - ASSERT_EQ(1u, vec2.size()); - - ASSERT_EQ(0u, arr.size()); - ASSERT_TRUE(arr.is_null()); -} - -} // namespace -} // namespace test -} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc index 8f2eb08..625c49c 100644 --- a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc +++ b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc @@ -9,18 +9,24 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/callback_helpers.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "mojo/public/cpp/bindings/associated_binding.h" -#include "mojo/public/cpp/bindings/associated_group.h" #include "mojo/public/cpp/bindings/associated_interface_ptr.h" #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h" #include "mojo/public/cpp/bindings/associated_interface_request.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/lib/multiplex_router.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h" +#include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h" #include "mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom.h" #include "testing/gtest/include/gtest/gtest.h" @@ -73,10 +79,8 @@ class IntegerSenderConnectionImpl : public IntegerSenderConnection { } void AsyncGetSender(const AsyncGetSenderCallback& callback) override { - AssociatedInterfaceRequest<IntegerSender> request; IntegerSenderAssociatedPtrInfo ptr_info; - binding_.associated_group()->CreateAssociatedInterface( - AssociatedGroup::WILL_PASS_PTR, &ptr_info, &request); + auto request = MakeRequest(&ptr_info); GetSender(std::move(request)); callback.Run(std::move(ptr_info)); } @@ -99,22 +103,42 @@ class AssociatedInterfaceTest : public testing::Test { template <typename T> AssociatedInterfacePtrInfo<T> EmulatePassingAssociatedPtrInfo( AssociatedInterfacePtrInfo<T> ptr_info, + scoped_refptr<MultiplexRouter> source, scoped_refptr<MultiplexRouter> target) { ScopedInterfaceEndpointHandle handle = ptr_info.PassHandle(); - CHECK(!handle.is_local()); - return AssociatedInterfacePtrInfo<T>( - target->CreateLocalEndpointHandle(handle.release()), - ptr_info.version()); + CHECK(handle.pending_association()); + auto id = source->AssociateInterface(std::move(handle)); + return AssociatedInterfacePtrInfo<T>(target->CreateLocalEndpointHandle(id), + ptr_info.version()); } - template <typename T> - AssociatedInterfaceRequest<T> EmulatePassingAssociatedRequest( - AssociatedInterfaceRequest<T> request, - scoped_refptr<MultiplexRouter> target) { - ScopedInterfaceEndpointHandle handle = request.PassHandle(); - CHECK(!handle.is_local()); - return MakeAssociatedRequest<T>( - target->CreateLocalEndpointHandle(handle.release())); + void CreateRouterPair(scoped_refptr<MultiplexRouter>* router0, + scoped_refptr<MultiplexRouter>* router1) { + MessagePipe pipe; + *router0 = new MultiplexRouter(std::move(pipe.handle0), + MultiplexRouter::MULTI_INTERFACE, true, + base::ThreadTaskRunnerHandle::Get()); + *router1 = new MultiplexRouter(std::move(pipe.handle1), + MultiplexRouter::MULTI_INTERFACE, false, + base::ThreadTaskRunnerHandle::Get()); + } + + void CreateIntegerSenderWithExistingRouters( + scoped_refptr<MultiplexRouter> router0, + IntegerSenderAssociatedPtrInfo* ptr_info0, + scoped_refptr<MultiplexRouter> router1, + IntegerSenderAssociatedRequest* request1) { + *request1 = MakeRequest(ptr_info0); + *ptr_info0 = EmulatePassingAssociatedPtrInfo(std::move(*ptr_info0), router1, + router0); + } + + void CreateIntegerSender(IntegerSenderAssociatedPtrInfo* ptr_info, + IntegerSenderAssociatedRequest* request) { + scoped_refptr<MultiplexRouter> router0; + scoped_refptr<MultiplexRouter> router1; + CreateRouterPair(&router0, &router1); + CreateIntegerSenderWithExistingRouters(router1, ptr_info, router0, request); } // Okay to call from any thread. @@ -158,30 +182,27 @@ base::Callback<void(int32_t)> ExpectValueSetFlagAndRunClosure( &DoExpectValueSetFlagAndRunClosure, expected_value, flag, closure); } +void Fail() { + FAIL() << "Unexpected connection error"; +} + TEST_F(AssociatedInterfaceTest, InterfacesAtBothEnds) { // Bind to the same pipe two associated interfaces, whose implementation lives // at different ends. Test that the two don't interfere with each other. - MessagePipe pipe; - scoped_refptr<MultiplexRouter> router0(new MultiplexRouter( - true, std::move(pipe.handle0), base::ThreadTaskRunnerHandle::Get())); - scoped_refptr<MultiplexRouter> router1(new MultiplexRouter( - false, std::move(pipe.handle1), base::ThreadTaskRunnerHandle::Get())); + scoped_refptr<MultiplexRouter> router0; + scoped_refptr<MultiplexRouter> router1; + CreateRouterPair(&router0, &router1); AssociatedInterfaceRequest<IntegerSender> request; IntegerSenderAssociatedPtrInfo ptr_info; - - router0->CreateAssociatedGroup()->CreateAssociatedInterface( - AssociatedGroup::WILL_PASS_PTR, &ptr_info, &request); - ptr_info = EmulatePassingAssociatedPtrInfo(std::move(ptr_info), router1); + CreateIntegerSenderWithExistingRouters(router1, &ptr_info, router0, &request); IntegerSenderImpl impl0(std::move(request)); AssociatedInterfacePtr<IntegerSender> ptr0; ptr0.Bind(std::move(ptr_info)); - router0->CreateAssociatedGroup()->CreateAssociatedInterface( - AssociatedGroup::WILL_PASS_REQUEST, &ptr_info, &request); - request = EmulatePassingAssociatedRequest(std::move(request), router1); + CreateIntegerSenderWithExistingRouters(router0, &ptr_info, router1, &request); IntegerSenderImpl impl1(std::move(request)); AssociatedInterfacePtr<IntegerSender> ptr1; @@ -358,19 +379,15 @@ TEST_F(AssociatedInterfaceTest, MultiThreadAccess) { const int32_t kMaxValue = 1000; MessagePipe pipe; - scoped_refptr<MultiplexRouter> router0(new MultiplexRouter( - true, std::move(pipe.handle0), base::ThreadTaskRunnerHandle::Get())); - scoped_refptr<MultiplexRouter> router1(new MultiplexRouter( - false, std::move(pipe.handle1), base::ThreadTaskRunnerHandle::Get())); + scoped_refptr<MultiplexRouter> router0; + scoped_refptr<MultiplexRouter> router1; + CreateRouterPair(&router0, &router1); AssociatedInterfaceRequest<IntegerSender> requests[4]; IntegerSenderAssociatedPtrInfo ptr_infos[4]; - for (size_t i = 0; i < 4; ++i) { - router0->CreateAssociatedGroup()->CreateAssociatedInterface( - AssociatedGroup::WILL_PASS_PTR, &ptr_infos[i], &requests[i]); - ptr_infos[i] = - EmulatePassingAssociatedPtrInfo(std::move(ptr_infos[i]), router1); + CreateIntegerSenderWithExistingRouters(router1, &ptr_infos[i], router0, + &requests[i]); } TestSender senders[4]; @@ -447,19 +464,15 @@ TEST_F(AssociatedInterfaceTest, FIFO) { const int32_t kMaxValue = 100; MessagePipe pipe; - scoped_refptr<MultiplexRouter> router0(new MultiplexRouter( - true, std::move(pipe.handle0), base::ThreadTaskRunnerHandle::Get())); - scoped_refptr<MultiplexRouter> router1(new MultiplexRouter( - false, std::move(pipe.handle1), base::ThreadTaskRunnerHandle::Get())); + scoped_refptr<MultiplexRouter> router0; + scoped_refptr<MultiplexRouter> router1; + CreateRouterPair(&router0, &router1); AssociatedInterfaceRequest<IntegerSender> requests[4]; IntegerSenderAssociatedPtrInfo ptr_infos[4]; - for (size_t i = 0; i < 4; ++i) { - router0->CreateAssociatedGroup()->CreateAssociatedInterface( - AssociatedGroup::WILL_PASS_PTR, &ptr_infos[i], &requests[i]); - ptr_infos[i] = - EmulatePassingAssociatedPtrInfo(std::move(ptr_infos[i]), router1); + CreateIntegerSenderWithExistingRouters(router1, &ptr_infos[i], router0, + &requests[i]); } TestSender senders[4]; @@ -538,11 +551,10 @@ void CaptureSenderPtrInfo(IntegerSenderAssociatedPtr* storage, TEST_F(AssociatedInterfaceTest, PassAssociatedInterfaces) { IntegerSenderConnectionPtr connection_ptr; - IntegerSenderConnectionImpl connection(GetProxy(&connection_ptr)); + IntegerSenderConnectionImpl connection(MakeRequest(&connection_ptr)); IntegerSenderAssociatedPtr sender0; - connection_ptr->GetSender( - GetProxy(&sender0, connection_ptr.associated_group())); + connection_ptr->GetSender(MakeRequest(&sender0)); int32_t echoed_value = 0; base::RunLoop run_loop; @@ -567,11 +579,10 @@ TEST_F(AssociatedInterfaceTest, PassAssociatedInterfaces) { TEST_F(AssociatedInterfaceTest, BindingWaitAndPauseWhenNoAssociatedInterfaces) { IntegerSenderConnectionPtr connection_ptr; - IntegerSenderConnectionImpl connection(GetProxy(&connection_ptr)); + IntegerSenderConnectionImpl connection(MakeRequest(&connection_ptr)); IntegerSenderAssociatedPtr sender0; - connection_ptr->GetSender( - GetProxy(&sender0, connection_ptr.associated_group())); + connection_ptr->GetSender(MakeRequest(&sender0)); EXPECT_FALSE(connection.binding()->HasAssociatedInterfaces()); // There are no associated interfaces running on the pipe yet. It is okay to @@ -589,6 +600,584 @@ TEST_F(AssociatedInterfaceTest, BindingWaitAndPauseWhenNoAssociatedInterfaces) { EXPECT_TRUE(connection.binding()->HasAssociatedInterfaces()); } +class PingServiceImpl : public PingService { + public: + explicit PingServiceImpl(PingServiceAssociatedRequest request) + : binding_(this, std::move(request)) {} + ~PingServiceImpl() override {} + + AssociatedBinding<PingService>& binding() { return binding_; } + + void set_ping_handler(const base::Closure& handler) { + ping_handler_ = handler; + } + + // PingService: + void Ping(const PingCallback& callback) override { + if (!ping_handler_.is_null()) + ping_handler_.Run(); + callback.Run(); + } + + private: + AssociatedBinding<PingService> binding_; + base::Closure ping_handler_; +}; + +class PingProviderImpl : public AssociatedPingProvider { + public: + explicit PingProviderImpl(AssociatedPingProviderRequest request) + : binding_(this, std::move(request)) {} + ~PingProviderImpl() override {} + + // AssociatedPingProvider: + void GetPing(PingServiceAssociatedRequest request) override { + ping_services_.emplace_back(new PingServiceImpl(std::move(request))); + + if (expected_bindings_count_ > 0 && + ping_services_.size() == expected_bindings_count_ && + !quit_waiting_.is_null()) { + expected_bindings_count_ = 0; + base::ResetAndReturn(&quit_waiting_).Run(); + } + } + + std::vector<std::unique_ptr<PingServiceImpl>>& ping_services() { + return ping_services_; + } + + void WaitForBindings(size_t count) { + DCHECK(quit_waiting_.is_null()); + + expected_bindings_count_ = count; + base::RunLoop loop; + quit_waiting_ = loop.QuitClosure(); + loop.Run(); + } + + private: + Binding<AssociatedPingProvider> binding_; + std::vector<std::unique_ptr<PingServiceImpl>> ping_services_; + size_t expected_bindings_count_ = 0; + base::Closure quit_waiting_; +}; + +class CallbackFilter : public MessageReceiver { + public: + explicit CallbackFilter(const base::Closure& callback) + : callback_(callback) {} + ~CallbackFilter() override {} + + static std::unique_ptr<CallbackFilter> Wrap(const base::Closure& callback) { + return base::MakeUnique<CallbackFilter>(callback); + } + + // MessageReceiver: + bool Accept(Message* message) override { + callback_.Run(); + return true; + } + + private: + const base::Closure callback_; +}; + +// Verifies that filters work as expected on associated bindings, i.e. that +// they're notified in order, before dispatch; and that each associated +// binding in a group operates with its own set of filters. +TEST_F(AssociatedInterfaceTest, BindingWithFilters) { + AssociatedPingProviderPtr provider; + PingProviderImpl provider_impl(MakeRequest(&provider)); + + PingServiceAssociatedPtr ping_a, ping_b; + provider->GetPing(MakeRequest(&ping_a)); + provider->GetPing(MakeRequest(&ping_b)); + provider_impl.WaitForBindings(2); + + ASSERT_EQ(2u, provider_impl.ping_services().size()); + PingServiceImpl& ping_a_impl = *provider_impl.ping_services()[0]; + PingServiceImpl& ping_b_impl = *provider_impl.ping_services()[1]; + + int a_status, b_status; + auto handler_helper = [] (int* a_status, int* b_status, int expected_a_status, + int new_a_status, int expected_b_status, + int new_b_status) { + EXPECT_EQ(expected_a_status, *a_status); + EXPECT_EQ(expected_b_status, *b_status); + *a_status = new_a_status; + *b_status = new_b_status; + }; + auto create_handler = [&] (int expected_a_status, int new_a_status, + int expected_b_status, int new_b_status) { + return base::Bind(handler_helper, &a_status, &b_status, expected_a_status, + new_a_status, expected_b_status, new_b_status); + }; + + ping_a_impl.binding().AddFilter( + CallbackFilter::Wrap(create_handler(0, 1, 0, 0))); + ping_a_impl.binding().AddFilter( + CallbackFilter::Wrap(create_handler(1, 2, 0, 0))); + ping_a_impl.set_ping_handler(create_handler(2, 3, 0, 0)); + + ping_b_impl.binding().AddFilter( + CallbackFilter::Wrap(create_handler(3, 3, 0, 1))); + ping_b_impl.binding().AddFilter( + CallbackFilter::Wrap(create_handler(3, 3, 1, 2))); + ping_b_impl.set_ping_handler(create_handler(3, 3, 2, 3)); + + for (int i = 0; i < 10; ++i) { + a_status = 0; + b_status = 0; + + { + base::RunLoop loop; + ping_a->Ping(loop.QuitClosure()); + loop.Run(); + } + + EXPECT_EQ(3, a_status); + EXPECT_EQ(0, b_status); + + { + base::RunLoop loop; + ping_b->Ping(loop.QuitClosure()); + loop.Run(); + } + + EXPECT_EQ(3, a_status); + EXPECT_EQ(3, b_status); + } +} + +TEST_F(AssociatedInterfaceTest, AssociatedPtrFlushForTesting) { + AssociatedInterfaceRequest<IntegerSender> request; + IntegerSenderAssociatedPtrInfo ptr_info; + CreateIntegerSender(&ptr_info, &request); + + IntegerSenderImpl impl0(std::move(request)); + AssociatedInterfacePtr<IntegerSender> ptr0; + ptr0.Bind(std::move(ptr_info)); + ptr0.set_connection_error_handler(base::Bind(&Fail)); + + bool ptr0_callback_run = false; + ptr0->Echo(123, ExpectValueSetFlagAndRunClosure( + 123, &ptr0_callback_run, base::Bind(&base::DoNothing))); + ptr0.FlushForTesting(); + EXPECT_TRUE(ptr0_callback_run); +} + +void SetBool(bool* value) { + *value = true; +} + +template <typename T> +void SetBoolWithUnusedParameter(bool* value, T unused) { + *value = true; +} + +TEST_F(AssociatedInterfaceTest, AssociatedPtrFlushForTestingWithClosedPeer) { + AssociatedInterfaceRequest<IntegerSender> request; + IntegerSenderAssociatedPtrInfo ptr_info; + CreateIntegerSender(&ptr_info, &request); + + AssociatedInterfacePtr<IntegerSender> ptr0; + ptr0.Bind(std::move(ptr_info)); + bool called = false; + ptr0.set_connection_error_handler(base::Bind(&SetBool, &called)); + request = nullptr; + + ptr0.FlushForTesting(); + EXPECT_TRUE(called); + ptr0.FlushForTesting(); +} + +TEST_F(AssociatedInterfaceTest, AssociatedBindingFlushForTesting) { + AssociatedInterfaceRequest<IntegerSender> request; + IntegerSenderAssociatedPtrInfo ptr_info; + CreateIntegerSender(&ptr_info, &request); + + IntegerSenderImpl impl0(std::move(request)); + impl0.set_connection_error_handler(base::Bind(&Fail)); + AssociatedInterfacePtr<IntegerSender> ptr0; + ptr0.Bind(std::move(ptr_info)); + + bool ptr0_callback_run = false; + ptr0->Echo(123, ExpectValueSetFlagAndRunClosure( + 123, &ptr0_callback_run, base::Bind(&base::DoNothing))); + // Because the flush is sent from the binding, it only guarantees that the + // request has been received, not the response. The second flush waits for the + // response to be received. + impl0.binding()->FlushForTesting(); + impl0.binding()->FlushForTesting(); + EXPECT_TRUE(ptr0_callback_run); +} + +TEST_F(AssociatedInterfaceTest, + AssociatedBindingFlushForTestingWithClosedPeer) { + scoped_refptr<MultiplexRouter> router0; + scoped_refptr<MultiplexRouter> router1; + CreateRouterPair(&router0, &router1); + + AssociatedInterfaceRequest<IntegerSender> request; + { + IntegerSenderAssociatedPtrInfo ptr_info; + CreateIntegerSenderWithExistingRouters(router1, &ptr_info, router0, + &request); + } + + IntegerSenderImpl impl(std::move(request)); + bool called = false; + impl.set_connection_error_handler(base::Bind(&SetBool, &called)); + impl.binding()->FlushForTesting(); + EXPECT_TRUE(called); + impl.binding()->FlushForTesting(); +} + +TEST_F(AssociatedInterfaceTest, BindingFlushForTesting) { + IntegerSenderConnectionPtr ptr; + IntegerSenderConnectionImpl impl(MakeRequest(&ptr)); + bool called = false; + ptr->AsyncGetSender(base::Bind( + &SetBoolWithUnusedParameter<IntegerSenderAssociatedPtrInfo>, &called)); + EXPECT_FALSE(called); + impl.binding()->set_connection_error_handler(base::Bind(&Fail)); + // Because the flush is sent from the binding, it only guarantees that the + // request has been received, not the response. The second flush waits for the + // response to be received. + impl.binding()->FlushForTesting(); + impl.binding()->FlushForTesting(); + EXPECT_TRUE(called); +} + +TEST_F(AssociatedInterfaceTest, BindingFlushForTestingWithClosedPeer) { + IntegerSenderConnectionPtr ptr; + IntegerSenderConnectionImpl impl(MakeRequest(&ptr)); + bool called = false; + impl.binding()->set_connection_error_handler(base::Bind(&SetBool, &called)); + ptr.reset(); + EXPECT_FALSE(called); + impl.binding()->FlushForTesting(); + EXPECT_TRUE(called); + impl.binding()->FlushForTesting(); +} + +TEST_F(AssociatedInterfaceTest, StrongBindingFlushForTesting) { + IntegerSenderConnectionPtr ptr; + auto binding = + MakeStrongBinding(base::MakeUnique<IntegerSenderConnectionImpl>( + IntegerSenderConnectionRequest{}), + MakeRequest(&ptr)); + bool called = false; + IntegerSenderAssociatedPtr sender_ptr; + ptr->GetSender(MakeRequest(&sender_ptr)); + sender_ptr->Echo(1, base::Bind(&SetBoolWithUnusedParameter<int>, &called)); + EXPECT_FALSE(called); + // Because the flush is sent from the binding, it only guarantees that the + // request has been received, not the response. The second flush waits for the + // response to be received. + ASSERT_TRUE(binding); + binding->FlushForTesting(); + ASSERT_TRUE(binding); + binding->FlushForTesting(); + EXPECT_TRUE(called); +} + +TEST_F(AssociatedInterfaceTest, StrongBindingFlushForTestingWithClosedPeer) { + IntegerSenderConnectionPtr ptr; + bool called = false; + auto binding = + MakeStrongBinding(base::MakeUnique<IntegerSenderConnectionImpl>( + IntegerSenderConnectionRequest{}), + MakeRequest(&ptr)); + binding->set_connection_error_handler(base::Bind(&SetBool, &called)); + ptr.reset(); + EXPECT_FALSE(called); + ASSERT_TRUE(binding); + binding->FlushForTesting(); + EXPECT_TRUE(called); + ASSERT_FALSE(binding); +} + +TEST_F(AssociatedInterfaceTest, PtrFlushForTesting) { + IntegerSenderConnectionPtr ptr; + IntegerSenderConnectionImpl impl(MakeRequest(&ptr)); + bool called = false; + ptr.set_connection_error_handler(base::Bind(&Fail)); + ptr->AsyncGetSender(base::Bind( + &SetBoolWithUnusedParameter<IntegerSenderAssociatedPtrInfo>, &called)); + EXPECT_FALSE(called); + ptr.FlushForTesting(); + EXPECT_TRUE(called); +} + +TEST_F(AssociatedInterfaceTest, PtrFlushForTestingWithClosedPeer) { + IntegerSenderConnectionPtr ptr; + MakeRequest(&ptr); + bool called = false; + ptr.set_connection_error_handler(base::Bind(&SetBool, &called)); + EXPECT_FALSE(called); + ptr.FlushForTesting(); + EXPECT_TRUE(called); + ptr.FlushForTesting(); +} + +TEST_F(AssociatedInterfaceTest, AssociatedBindingConnectionErrorWithReason) { + AssociatedInterfaceRequest<IntegerSender> request; + IntegerSenderAssociatedPtrInfo ptr_info; + CreateIntegerSender(&ptr_info, &request); + + IntegerSenderImpl impl(std::move(request)); + AssociatedInterfacePtr<IntegerSender> ptr; + ptr.Bind(std::move(ptr_info)); + + base::RunLoop run_loop; + impl.binding()->set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(123u, custom_reason); + EXPECT_EQ("farewell", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + ptr.ResetWithReason(123u, "farewell"); + + run_loop.Run(); +} + +TEST_F(AssociatedInterfaceTest, + PendingAssociatedBindingConnectionErrorWithReason) { + // Test that AssociatedBinding is notified with connection error when the + // interface hasn't associated with a message pipe and the peer is closed. + + IntegerSenderAssociatedPtr ptr; + IntegerSenderImpl impl(MakeRequest(&ptr)); + + base::RunLoop run_loop; + impl.binding()->set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(123u, custom_reason); + EXPECT_EQ("farewell", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + ptr.ResetWithReason(123u, "farewell"); + + run_loop.Run(); +} + +TEST_F(AssociatedInterfaceTest, AssociatedPtrConnectionErrorWithReason) { + AssociatedInterfaceRequest<IntegerSender> request; + IntegerSenderAssociatedPtrInfo ptr_info; + CreateIntegerSender(&ptr_info, &request); + + IntegerSenderImpl impl(std::move(request)); + AssociatedInterfacePtr<IntegerSender> ptr; + ptr.Bind(std::move(ptr_info)); + + base::RunLoop run_loop; + ptr.set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(456u, custom_reason); + EXPECT_EQ("farewell", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + impl.binding()->CloseWithReason(456u, "farewell"); + + run_loop.Run(); +} + +TEST_F(AssociatedInterfaceTest, PendingAssociatedPtrConnectionErrorWithReason) { + // Test that AssociatedInterfacePtr is notified with connection error when the + // interface hasn't associated with a message pipe and the peer is closed. + + IntegerSenderAssociatedPtr ptr; + auto request = MakeRequest(&ptr); + + base::RunLoop run_loop; + ptr.set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(456u, custom_reason); + EXPECT_EQ("farewell", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + request.ResetWithReason(456u, "farewell"); + + run_loop.Run(); +} + +TEST_F(AssociatedInterfaceTest, AssociatedRequestResetWithReason) { + AssociatedInterfaceRequest<IntegerSender> request; + IntegerSenderAssociatedPtrInfo ptr_info; + CreateIntegerSender(&ptr_info, &request); + + AssociatedInterfacePtr<IntegerSender> ptr; + ptr.Bind(std::move(ptr_info)); + + base::RunLoop run_loop; + ptr.set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(789u, custom_reason); + EXPECT_EQ("long time no see", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + request.ResetWithReason(789u, "long time no see"); + + run_loop.Run(); +} + +TEST_F(AssociatedInterfaceTest, ThreadSafeAssociatedInterfacePtr) { + IntegerSenderConnectionPtr connection_ptr; + IntegerSenderConnectionImpl connection(MakeRequest(&connection_ptr)); + + IntegerSenderAssociatedPtr sender; + connection_ptr->GetSender(MakeRequest(&sender)); + + scoped_refptr<ThreadSafeIntegerSenderAssociatedPtr> thread_safe_sender = + ThreadSafeIntegerSenderAssociatedPtr::Create(std::move(sender)); + + { + // Test the thread safe pointer can be used from the interface ptr thread. + int32_t echoed_value = 0; + base::RunLoop run_loop; + (*thread_safe_sender) + ->Echo(123, base::Bind(&CaptureInt32, &echoed_value, + run_loop.QuitClosure())); + run_loop.Run(); + EXPECT_EQ(123, echoed_value); + } + + // Test the thread safe pointer can be used from another thread. + base::RunLoop run_loop; + base::Thread other_thread("service test thread"); + other_thread.Start(); + + auto run_method = base::Bind( + [](const scoped_refptr<base::TaskRunner>& main_task_runner, + const base::Closure& quit_closure, + const scoped_refptr<ThreadSafeIntegerSenderAssociatedPtr>& + thread_safe_sender) { + auto done_callback = base::Bind( + [](const scoped_refptr<base::TaskRunner>& main_task_runner, + const base::Closure& quit_closure, + base::PlatformThreadId thread_id, int32_t result) { + EXPECT_EQ(123, result); + // Validate the callback is invoked on the calling thread. + EXPECT_EQ(thread_id, base::PlatformThread::CurrentId()); + // Notify the run_loop to quit. + main_task_runner->PostTask(FROM_HERE, quit_closure); + }); + (*thread_safe_sender) + ->Echo(123, + base::Bind(done_callback, main_task_runner, quit_closure, + base::PlatformThread::CurrentId())); + }, + base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure(), + thread_safe_sender); + other_thread.message_loop()->task_runner()->PostTask(FROM_HERE, run_method); + + // Block until the method callback is called on the background thread. + run_loop.Run(); +} + +struct ForwarderTestContext { + IntegerSenderConnectionPtr connection_ptr; + std::unique_ptr<IntegerSenderConnectionImpl> interface_impl; + IntegerSenderAssociatedRequest sender_request; +}; + +TEST_F(AssociatedInterfaceTest, + ThreadSafeAssociatedInterfacePtrWithTaskRunner) { + // Start the thread from where we'll bind the interface pointer. + base::Thread other_thread("service test thread"); + other_thread.Start(); + const scoped_refptr<base::SingleThreadTaskRunner>& other_thread_task_runner = + other_thread.message_loop()->task_runner(); + + ForwarderTestContext* context = new ForwarderTestContext(); + IntegerSenderAssociatedPtrInfo sender_info; + base::WaitableEvent sender_info_bound_event( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + auto setup = [](base::WaitableEvent* sender_info_bound_event, + IntegerSenderAssociatedPtrInfo* sender_info, + ForwarderTestContext* context) { + context->interface_impl = base::MakeUnique<IntegerSenderConnectionImpl>( + MakeRequest(&context->connection_ptr)); + + auto sender_request = MakeRequest(sender_info); + context->connection_ptr->GetSender(std::move(sender_request)); + + // Unblock the main thread as soon as |sender_info| is set. + sender_info_bound_event->Signal(); + }; + other_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(setup, &sender_info_bound_event, &sender_info, context)); + sender_info_bound_event.Wait(); + + // Create a ThreadSafeAssociatedPtr that binds on the background thread and is + // associated with |connection_ptr| there. + scoped_refptr<ThreadSafeIntegerSenderAssociatedPtr> thread_safe_ptr = + ThreadSafeIntegerSenderAssociatedPtr::Create(std::move(sender_info), + other_thread_task_runner); + + // Issue a call on the thread-safe ptr immediately. Note that this may happen + // before the interface is bound on the background thread, and that must be + // OK. + { + auto echo_callback = + base::Bind([](const base::Closure& quit_closure, int32_t result) { + EXPECT_EQ(123, result); + quit_closure.Run(); + }); + base::RunLoop run_loop; + (*thread_safe_ptr) + ->Echo(123, base::Bind(echo_callback, run_loop.QuitClosure())); + + // Block until the method callback is called. + run_loop.Run(); + } + + other_thread_task_runner->DeleteSoon(FROM_HERE, context); + + // Reset the pointer now so the InterfacePtr associated resources can be + // deleted before the background thread's message loop is invalidated. + thread_safe_ptr = nullptr; +} + +class DiscardingAssociatedPingProviderProvider + : public AssociatedPingProviderProvider { + public: + void GetPingProvider( + AssociatedPingProviderAssociatedRequest request) override {} +}; + +TEST_F(AssociatedInterfaceTest, CloseWithoutBindingAssociatedRequest) { + DiscardingAssociatedPingProviderProvider ping_provider_provider; + mojo::Binding<AssociatedPingProviderProvider> binding( + &ping_provider_provider); + auto provider_provider = binding.CreateInterfacePtrAndBind(); + AssociatedPingProviderAssociatedPtr provider; + provider_provider->GetPingProvider(mojo::MakeRequest(&provider)); + PingServiceAssociatedPtr ping; + provider->GetPing(mojo::MakeRequest(&ping)); + base::RunLoop run_loop; + ping.set_connection_error_handler(run_loop.QuitClosure()); + run_loop.Run(); +} + } // namespace } // namespace test } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/bind_task_runner_unittest.cc b/mojo/public/cpp/bindings/tests/bind_task_runner_unittest.cc index dab64f0..0c777ec 100644 --- a/mojo/public/cpp/bindings/tests/bind_task_runner_unittest.cc +++ b/mojo/public/cpp/bindings/tests/bind_task_runner_unittest.cc @@ -10,7 +10,6 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/platform_thread.h" #include "mojo/public/cpp/bindings/associated_binding.h" -#include "mojo/public/cpp/bindings/associated_group.h" #include "mojo/public/cpp/bindings/associated_interface_ptr.h" #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h" #include "mojo/public/cpp/bindings/associated_interface_request.h" @@ -187,7 +186,7 @@ class BindTaskRunnerTest : public testing::Test { binding_task_runner_ = scoped_refptr<TestTaskRunner>(new TestTaskRunner); ptr_task_runner_ = scoped_refptr<TestTaskRunner>(new TestTaskRunner); - auto request = GetProxy(&ptr_, ptr_task_runner_); + auto request = MakeRequest(&ptr_, ptr_task_runner_); impl_.reset(new ImplType(std::move(request), binding_task_runner_)); } @@ -213,7 +212,7 @@ class AssociatedBindTaskRunnerTest : public testing::Test { sender_ptr_task_runner_ = scoped_refptr<TestTaskRunner>(new TestTaskRunner); auto connection_request = - GetProxy(&connection_ptr_, connection_ptr_task_runner_); + MakeRequest(&connection_ptr_, connection_ptr_task_runner_); connection_impl_.reset(new IntegerSenderConnectionImpl( std::move(connection_request), connection_binding_task_runner_, sender_binding_task_runner_)); @@ -222,9 +221,8 @@ class AssociatedBindTaskRunnerTest : public testing::Test { base::Bind(&AssociatedBindTaskRunnerTest::QuitTaskRunner, base::Unretained(this))); - connection_ptr_->GetSender(GetProxy(&sender_ptr_, - connection_ptr_.associated_group(), - sender_ptr_task_runner_)); + connection_ptr_->GetSender( + MakeRequest(&sender_ptr_, sender_ptr_task_runner_)); connection_binding_task_runner_->Run(); } diff --git a/mojo/public/cpp/bindings/tests/binding_callback_unittest.cc b/mojo/public/cpp/bindings/tests/binding_callback_unittest.cc index 02b082a..43122ce 100644 --- a/mojo/public/cpp/bindings/tests/binding_callback_unittest.cc +++ b/mojo/public/cpp/bindings/tests/binding_callback_unittest.cc @@ -9,10 +9,10 @@ #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/test/gtest_util.h" #include "build/build_config.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_ptr.h" -#include "mojo/public/cpp/bindings/string.h" #include "mojo/public/cpp/system/message_pipe.h" #include "mojo/public/cpp/test_support/test_support.h" #include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h" @@ -140,7 +140,7 @@ class BindingCallbackTest : public testing::Test { TEST_F(BindingCallbackTest, Basic) { // Create the ServerImpl and the Binding. InterfaceImpl server_impl; - Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_)); + Binding<sample::Provider> binding(&server_impl, MakeRequest(&interface_ptr_)); // Initialize the test values. server_impl.resetLastServerValueSeen(); @@ -199,7 +199,8 @@ TEST_F(BindingCallbackTest, DeleteBindingThenRunCallback) { base::RunLoop run_loop; { // Create the binding in an inner scope so it can be deleted first. - Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_)); + Binding<sample::Provider> binding(&server_impl, + MakeRequest(&interface_ptr_)); interface_ptr_.set_connection_error_handler(run_loop.QuitClosure()); // Initialize the test values. @@ -244,7 +245,8 @@ TEST_F(BindingCallbackTest, DeleteBindingThenDeleteCallback) { InterfaceImpl server_impl; { // Create the binding in an inner scope so it can be deleted first. - Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_)); + Binding<sample::Provider> binding(&server_impl, + MakeRequest(&interface_ptr_)); // Initialize the test values. server_impl.resetLastServerValueSeen(); @@ -275,7 +277,7 @@ TEST_F(BindingCallbackTest, DeleteBindingThenDeleteCallback) { TEST_F(BindingCallbackTest, CloseBindingBeforeDeletingCallback) { // Create the ServerImpl and the Binding. InterfaceImpl server_impl; - Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_)); + Binding<sample::Provider> binding(&server_impl, MakeRequest(&interface_ptr_)); // Initialize the test values. server_impl.resetLastServerValueSeen(); @@ -310,7 +312,7 @@ TEST_F(BindingCallbackTest, CloseBindingBeforeDeletingCallback) { TEST_F(BindingCallbackTest, DeleteCallbackBeforeBindingDeathTest) { // Create the ServerImpl and the Binding. InterfaceImpl server_impl; - Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_)); + Binding<sample::Provider> binding(&server_impl, MakeRequest(&interface_ptr_)); // Initialize the test values. server_impl.resetLastServerValueSeen(); @@ -328,17 +330,7 @@ TEST_F(BindingCallbackTest, DeleteCallbackBeforeBindingDeathTest) { EXPECT_EQ(7, server_impl.last_server_value_seen()); EXPECT_EQ(0, last_client_callback_value_seen_); -#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && !defined(OS_ANDROID) - // Delete the callback without running it. This should cause a crash in debug - // builds due to a DCHECK. - std::string regex("Check failed: !is_valid"); -#if defined(OS_WIN) - // TODO(msw): Fix MOJO_DCHECK logs and EXPECT_DEATH* on Win: crbug.com/535014 - regex.clear(); -#endif // OS_WIN - EXPECT_DEATH_IF_SUPPORTED(server_impl.DeleteCallback(), regex.c_str()); -#endif // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && - // !defined(OS_ANDROID) + EXPECT_DCHECK_DEATH(server_impl.DeleteCallback()); } } // namespace diff --git a/mojo/public/cpp/bindings/tests/binding_set_unittest.cc b/mojo/public/cpp/bindings/tests/binding_set_unittest.cc new file mode 100644 index 0000000..07acfbe --- /dev/null +++ b/mojo/public/cpp/bindings/tests/binding_set_unittest.cc @@ -0,0 +1,416 @@ +// 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 <memory> +#include <utility> + +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "mojo/public/cpp/bindings/associated_binding_set.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/strong_binding_set.h" +#include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h" +#include "mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace test { +namespace { + +class BindingSetTest : public testing::Test { + public: + BindingSetTest() {} + ~BindingSetTest() override {} + + base::MessageLoop& loop() { return loop_; } + + private: + base::MessageLoop loop_; + + DISALLOW_COPY_AND_ASSIGN(BindingSetTest); +}; + +template <typename BindingSetType, typename ContextType> +void ExpectContextHelper(BindingSetType* binding_set, + ContextType expected_context) { + EXPECT_EQ(expected_context, binding_set->dispatch_context()); +} + +template <typename BindingSetType, typename ContextType> +base::Closure ExpectContext(BindingSetType* binding_set, + ContextType expected_context) { + return base::Bind( + &ExpectContextHelper<BindingSetType, ContextType>, binding_set, + expected_context); +} + +base::Closure Sequence(const base::Closure& first, + const base::Closure& second) { + return base::Bind( + [] (const base::Closure& first, const base::Closure& second) { + first.Run(); + second.Run(); + }, first, second); +} + +class PingImpl : public PingService { + public: + PingImpl() {} + ~PingImpl() override {} + + void set_ping_handler(const base::Closure& handler) { + ping_handler_ = handler; + } + + private: + // PingService: + void Ping(const PingCallback& callback) override { + if (!ping_handler_.is_null()) + ping_handler_.Run(); + callback.Run(); + } + + base::Closure ping_handler_; +}; + +TEST_F(BindingSetTest, BindingSetContext) { + PingImpl impl; + + BindingSet<PingService, int> bindings; + PingServicePtr ping_a, ping_b; + bindings.AddBinding(&impl, MakeRequest(&ping_a), 1); + bindings.AddBinding(&impl, MakeRequest(&ping_b), 2); + + { + impl.set_ping_handler(ExpectContext(&bindings, 1)); + base::RunLoop loop; + ping_a->Ping(loop.QuitClosure()); + loop.Run(); + } + + { + impl.set_ping_handler(ExpectContext(&bindings, 2)); + base::RunLoop loop; + ping_b->Ping(loop.QuitClosure()); + loop.Run(); + } + + { + base::RunLoop loop; + bindings.set_connection_error_handler( + Sequence(ExpectContext(&bindings, 1), loop.QuitClosure())); + ping_a.reset(); + loop.Run(); + } + + { + base::RunLoop loop; + bindings.set_connection_error_handler( + Sequence(ExpectContext(&bindings, 2), loop.QuitClosure())); + ping_b.reset(); + loop.Run(); + } + + EXPECT_TRUE(bindings.empty()); +} + +TEST_F(BindingSetTest, BindingSetConnectionErrorWithReason) { + PingImpl impl; + PingServicePtr ptr; + BindingSet<PingService> bindings; + bindings.AddBinding(&impl, MakeRequest(&ptr)); + + base::RunLoop run_loop; + bindings.set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(1024u, custom_reason); + EXPECT_EQ("bye", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + ptr.ResetWithReason(1024u, "bye"); +} + +class PingProviderImpl : public AssociatedPingProvider, public PingService { + public: + PingProviderImpl() {} + ~PingProviderImpl() override {} + + void set_new_ping_context(int context) { new_ping_context_ = context; } + + void set_new_ping_handler(const base::Closure& handler) { + new_ping_handler_ = handler; + } + + void set_ping_handler(const base::Closure& handler) { + ping_handler_ = handler; + } + + AssociatedBindingSet<PingService, int>& ping_bindings() { + return ping_bindings_; + } + + private: + // AssociatedPingProvider: + void GetPing(PingServiceAssociatedRequest request) override { + ping_bindings_.AddBinding(this, std::move(request), new_ping_context_); + if (!new_ping_handler_.is_null()) + new_ping_handler_.Run(); + } + + // PingService: + void Ping(const PingCallback& callback) override { + if (!ping_handler_.is_null()) + ping_handler_.Run(); + callback.Run(); + } + + AssociatedBindingSet<PingService, int> ping_bindings_; + int new_ping_context_ = -1; + base::Closure ping_handler_; + base::Closure new_ping_handler_; +}; + +TEST_F(BindingSetTest, AssociatedBindingSetContext) { + AssociatedPingProviderPtr provider; + PingProviderImpl impl; + Binding<AssociatedPingProvider> binding(&impl, MakeRequest(&provider)); + + PingServiceAssociatedPtr ping_a; + { + base::RunLoop loop; + impl.set_new_ping_context(1); + impl.set_new_ping_handler(loop.QuitClosure()); + provider->GetPing(MakeRequest(&ping_a)); + loop.Run(); + } + + PingServiceAssociatedPtr ping_b; + { + base::RunLoop loop; + impl.set_new_ping_context(2); + impl.set_new_ping_handler(loop.QuitClosure()); + provider->GetPing(MakeRequest(&ping_b)); + loop.Run(); + } + + { + impl.set_ping_handler(ExpectContext(&impl.ping_bindings(), 1)); + base::RunLoop loop; + ping_a->Ping(loop.QuitClosure()); + loop.Run(); + } + + { + impl.set_ping_handler(ExpectContext(&impl.ping_bindings(), 2)); + base::RunLoop loop; + ping_b->Ping(loop.QuitClosure()); + loop.Run(); + } + + { + base::RunLoop loop; + impl.ping_bindings().set_connection_error_handler( + Sequence(ExpectContext(&impl.ping_bindings(), 1), loop.QuitClosure())); + ping_a.reset(); + loop.Run(); + } + + { + base::RunLoop loop; + impl.ping_bindings().set_connection_error_handler( + Sequence(ExpectContext(&impl.ping_bindings(), 2), loop.QuitClosure())); + ping_b.reset(); + loop.Run(); + } + + EXPECT_TRUE(impl.ping_bindings().empty()); +} + +TEST_F(BindingSetTest, MasterInterfaceBindingSetContext) { + AssociatedPingProviderPtr provider_a, provider_b; + PingProviderImpl impl; + BindingSet<AssociatedPingProvider, int> bindings; + + bindings.AddBinding(&impl, MakeRequest(&provider_a), 1); + bindings.AddBinding(&impl, MakeRequest(&provider_b), 2); + + { + PingServiceAssociatedPtr ping; + base::RunLoop loop; + impl.set_new_ping_handler( + Sequence(ExpectContext(&bindings, 1), loop.QuitClosure())); + provider_a->GetPing(MakeRequest(&ping)); + loop.Run(); + } + + { + PingServiceAssociatedPtr ping; + base::RunLoop loop; + impl.set_new_ping_handler( + Sequence(ExpectContext(&bindings, 2), loop.QuitClosure())); + provider_b->GetPing(MakeRequest(&ping)); + loop.Run(); + } + + { + base::RunLoop loop; + bindings.set_connection_error_handler( + Sequence(ExpectContext(&bindings, 1), loop.QuitClosure())); + provider_a.reset(); + loop.Run(); + } + + { + base::RunLoop loop; + bindings.set_connection_error_handler( + Sequence(ExpectContext(&bindings, 2), loop.QuitClosure())); + provider_b.reset(); + loop.Run(); + } + + EXPECT_TRUE(bindings.empty()); +} + +TEST_F(BindingSetTest, PreDispatchHandler) { + PingImpl impl; + + BindingSet<PingService, int> bindings; + PingServicePtr ping_a, ping_b; + bindings.AddBinding(&impl, MakeRequest(&ping_a), 1); + bindings.AddBinding(&impl, MakeRequest(&ping_b), 2); + + { + bindings.set_pre_dispatch_handler(base::Bind([] (const int& context) { + EXPECT_EQ(1, context); + })); + base::RunLoop loop; + ping_a->Ping(loop.QuitClosure()); + loop.Run(); + } + + { + bindings.set_pre_dispatch_handler(base::Bind([] (const int& context) { + EXPECT_EQ(2, context); + })); + base::RunLoop loop; + ping_b->Ping(loop.QuitClosure()); + loop.Run(); + } + + { + base::RunLoop loop; + bindings.set_pre_dispatch_handler( + base::Bind([](base::RunLoop* loop, const int& context) { + EXPECT_EQ(1, context); + loop->Quit(); + }, &loop)); + ping_a.reset(); + loop.Run(); + } + + { + base::RunLoop loop; + bindings.set_pre_dispatch_handler( + base::Bind([](base::RunLoop* loop, const int& context) { + EXPECT_EQ(2, context); + loop->Quit(); + }, &loop)); + ping_b.reset(); + loop.Run(); + } + + EXPECT_TRUE(bindings.empty()); +} + +TEST_F(BindingSetTest, AssociatedBindingSetConnectionErrorWithReason) { + AssociatedPingProviderPtr master_ptr; + PingProviderImpl master_impl; + Binding<AssociatedPingProvider> master_binding(&master_impl, &master_ptr); + + base::RunLoop run_loop; + master_impl.ping_bindings().set_connection_error_with_reason_handler( + base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(2048u, custom_reason); + EXPECT_EQ("bye", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + PingServiceAssociatedPtr ptr; + master_ptr->GetPing(MakeRequest(&ptr)); + + ptr.ResetWithReason(2048u, "bye"); + + run_loop.Run(); +} + +class PingInstanceCounter : public PingService { + public: + PingInstanceCounter() { ++instance_count; } + ~PingInstanceCounter() override { --instance_count; } + + void Ping(const PingCallback& callback) override {} + + static int instance_count; +}; +int PingInstanceCounter::instance_count = 0; + +TEST_F(BindingSetTest, StrongBinding_Destructor) { + PingServicePtr ping_a, ping_b; + auto bindings = base::MakeUnique<StrongBindingSet<PingService>>(); + + bindings->AddBinding(base::MakeUnique<PingInstanceCounter>(), + mojo::MakeRequest(&ping_a)); + EXPECT_EQ(1, PingInstanceCounter::instance_count); + + bindings->AddBinding(base::MakeUnique<PingInstanceCounter>(), + mojo::MakeRequest(&ping_b)); + EXPECT_EQ(2, PingInstanceCounter::instance_count); + + bindings.reset(); + EXPECT_EQ(0, PingInstanceCounter::instance_count); +} + +TEST_F(BindingSetTest, StrongBinding_ConnectionError) { + PingServicePtr ping_a, ping_b; + StrongBindingSet<PingService> bindings; + bindings.AddBinding(base::MakeUnique<PingInstanceCounter>(), + mojo::MakeRequest(&ping_a)); + bindings.AddBinding(base::MakeUnique<PingInstanceCounter>(), + mojo::MakeRequest(&ping_b)); + EXPECT_EQ(2, PingInstanceCounter::instance_count); + + ping_a.reset(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, PingInstanceCounter::instance_count); + + ping_b.reset(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0, PingInstanceCounter::instance_count); +} + +TEST_F(BindingSetTest, StrongBinding_RemoveBinding) { + PingServicePtr ping_a, ping_b; + StrongBindingSet<PingService> bindings; + BindingId binding_id_a = bindings.AddBinding( + base::MakeUnique<PingInstanceCounter>(), mojo::MakeRequest(&ping_a)); + BindingId binding_id_b = bindings.AddBinding( + base::MakeUnique<PingInstanceCounter>(), mojo::MakeRequest(&ping_b)); + EXPECT_EQ(2, PingInstanceCounter::instance_count); + + EXPECT_TRUE(bindings.RemoveBinding(binding_id_a)); + EXPECT_EQ(1, PingInstanceCounter::instance_count); + + EXPECT_TRUE(bindings.RemoveBinding(binding_id_b)); + EXPECT_EQ(0, PingInstanceCounter::instance_count); +} + +} // namespace +} // namespace test +} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/binding_unittest.cc b/mojo/public/cpp/bindings/tests/binding_unittest.cc index 4838ee8..e76993b 100644 --- a/mojo/public/cpp/bindings/tests/binding_unittest.cc +++ b/mojo/public/cpp/bindings/tests/binding_unittest.cc @@ -11,9 +11,12 @@ #include <utility> #include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h" #include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h" #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h" #include "testing/gtest/include/gtest/gtest.h" @@ -63,7 +66,8 @@ void DoSetFlagAndRunClosure(bool* flag, const base::Closure& closure, Args... args) { *flag = true; - closure.Run(); + if (!closure.is_null()) + closure.Run(); } template <typename... Args> @@ -80,7 +84,7 @@ using BindingTest = BindingTestBase; TEST_F(BindingTest, Close) { bool called = false; sample::ServicePtr ptr; - auto request = GetProxy(&ptr); + auto request = MakeRequest(&ptr); base::RunLoop run_loop; ptr.set_connection_error_handler( SetFlagAndRunClosure(&called, run_loop.QuitClosure())); @@ -98,7 +102,7 @@ TEST_F(BindingTest, DestroyClosesMessagePipe) { bool encountered_error = false; ServiceImpl impl; sample::ServicePtr ptr; - auto request = GetProxy(&ptr); + auto request = MakeRequest(&ptr); base::RunLoop run_loop; ptr.set_connection_error_handler( SetFlagAndRunClosure(&encountered_error, run_loop.QuitClosure())); @@ -134,7 +138,7 @@ TEST_F(BindingTest, ConnectionError) { { ServiceImpl impl; sample::ServicePtr ptr; - Binding<sample::Service> binding(&impl, GetProxy(&ptr)); + Binding<sample::Service> binding(&impl, MakeRequest(&ptr)); base::RunLoop run_loop; binding.set_connection_error_handler( SetFlagAndRunClosure(&called, run_loop.QuitClosure())); @@ -153,7 +157,7 @@ TEST_F(BindingTest, ConnectionError) { TEST_F(BindingTest, CloseDoesntCallConnectionErrorHandler) { ServiceImpl impl; sample::ServicePtr ptr; - Binding<sample::Service> binding(&impl, GetProxy(&ptr)); + Binding<sample::Service> binding(&impl, MakeRequest(&ptr)); bool called = false; binding.set_connection_error_handler(SetFlagAndRunClosure(&called)); binding.Close(); @@ -200,7 +204,7 @@ TEST_F(BindingTest, SelfDeleteOnConnectionError) { // This should delete itself on connection error. base::RunLoop run_loop; new ServiceImplWithBinding(&was_deleted, run_loop.QuitClosure(), - GetProxy(&ptr)); + MakeRequest(&ptr)); ptr.reset(); EXPECT_FALSE(was_deleted); run_loop.Run(); @@ -211,7 +215,7 @@ TEST_F(BindingTest, SelfDeleteOnConnectionError) { TEST_F(BindingTest, Unbind) { ServiceImpl impl; sample::ServicePtr ptr; - Binding<sample::Service> binding(&impl, GetProxy(&ptr)); + Binding<sample::Service> binding(&impl, MakeRequest(&ptr)); bool called = false; base::RunLoop run_loop; @@ -269,7 +273,7 @@ TEST_F(BindingTest, PauseResume) { bool called = false; base::RunLoop run_loop; sample::ServicePtr ptr; - auto request = GetProxy(&ptr); + auto request = MakeRequest(&ptr); ServiceImpl impl; Binding<sample::Service> binding(&impl, std::move(request)); binding.PauseIncomingMethodCallProcessing(); @@ -292,7 +296,7 @@ TEST_F(BindingTest, ErrorHandleNotRunWhilePaused) { bool called = false; base::RunLoop run_loop; sample::ServicePtr ptr; - auto request = GetProxy(&ptr); + auto request = MakeRequest(&ptr); ServiceImpl impl; Binding<sample::Service> binding(&impl, std::move(request)); binding.set_connection_error_handler( @@ -310,6 +314,177 @@ TEST_F(BindingTest, ErrorHandleNotRunWhilePaused) { EXPECT_TRUE(called); } +class PingServiceImpl : public test::PingService { + public: + PingServiceImpl() {} + ~PingServiceImpl() override {} + + // test::PingService: + void Ping(const PingCallback& callback) override { + if (!ping_handler_.is_null()) + ping_handler_.Run(); + callback.Run(); + } + + void set_ping_handler(const base::Closure& handler) { + ping_handler_ = handler; + } + + private: + base::Closure ping_handler_; + + DISALLOW_COPY_AND_ASSIGN(PingServiceImpl); +}; + +class CallbackFilter : public MessageReceiver { + public: + explicit CallbackFilter(const base::Closure& callback) + : callback_(callback) {} + ~CallbackFilter() override {} + + static std::unique_ptr<CallbackFilter> Wrap(const base::Closure& callback) { + return base::MakeUnique<CallbackFilter>(callback); + } + + // MessageReceiver: + bool Accept(Message* message) override { + callback_.Run(); + return true; + } + + private: + const base::Closure callback_; +}; + +// Verifies that message filters are notified in the order they were added and +// are always notified before a message is dispatched. +TEST_F(BindingTest, MessageFilter) { + test::PingServicePtr ptr; + PingServiceImpl impl; + mojo::Binding<test::PingService> binding(&impl, MakeRequest(&ptr)); + + int status = 0; + auto handler_helper = [] (int* status, int expected_status, int new_status) { + EXPECT_EQ(expected_status, *status); + *status = new_status; + }; + auto create_handler = [&] (int expected_status, int new_status) { + return base::Bind(handler_helper, &status, expected_status, new_status); + }; + + binding.AddFilter(CallbackFilter::Wrap(create_handler(0, 1))); + binding.AddFilter(CallbackFilter::Wrap(create_handler(1, 2))); + impl.set_ping_handler(create_handler(2, 3)); + + for (int i = 0; i < 10; ++i) { + status = 0; + base::RunLoop loop; + ptr->Ping(loop.QuitClosure()); + loop.Run(); + EXPECT_EQ(3, status); + } +} + +void Fail() { + FAIL() << "Unexpected connection error"; +} + +TEST_F(BindingTest, FlushForTesting) { + bool called = false; + sample::ServicePtr ptr; + auto request = MakeRequest(&ptr); + ServiceImpl impl; + Binding<sample::Service> binding(&impl, std::move(request)); + binding.set_connection_error_handler(base::Bind(&Fail)); + + ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, + SetFlagAndRunClosure<int32_t>(&called)); + EXPECT_FALSE(called); + // Because the flush is sent from the binding, it only guarantees that the + // request has been received, not the response. The second flush waits for the + // response to be received. + binding.FlushForTesting(); + binding.FlushForTesting(); + EXPECT_TRUE(called); +} + +TEST_F(BindingTest, FlushForTestingWithClosedPeer) { + bool called = false; + sample::ServicePtr ptr; + auto request = MakeRequest(&ptr); + ServiceImpl impl; + Binding<sample::Service> binding(&impl, std::move(request)); + binding.set_connection_error_handler(SetFlagAndRunClosure(&called)); + ptr.reset(); + + EXPECT_FALSE(called); + binding.FlushForTesting(); + EXPECT_TRUE(called); + binding.FlushForTesting(); +} + +TEST_F(BindingTest, ConnectionErrorWithReason) { + sample::ServicePtr ptr; + auto request = MakeRequest(&ptr); + ServiceImpl impl; + Binding<sample::Service> binding(&impl, std::move(request)); + + base::RunLoop run_loop; + binding.set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(1234u, custom_reason); + EXPECT_EQ("hello", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + ptr.ResetWithReason(1234u, "hello"); + + run_loop.Run(); +} + +template <typename T> +struct WeakPtrImplRefTraits { + using PointerType = base::WeakPtr<T>; + + static bool IsNull(const base::WeakPtr<T>& ptr) { return !ptr; } + static T* GetRawPointer(base::WeakPtr<T>* ptr) { return ptr->get(); } +}; + +template <typename T> +using WeakBinding = Binding<T, WeakPtrImplRefTraits<T>>; + +TEST_F(BindingTest, CustomImplPointerType) { + PingServiceImpl impl; + base::WeakPtrFactory<test::PingService> weak_factory(&impl); + + test::PingServicePtr proxy; + WeakBinding<test::PingService> binding(weak_factory.GetWeakPtr(), + MakeRequest(&proxy)); + + { + // Ensure the binding is functioning. + base::RunLoop run_loop; + proxy->Ping(run_loop.QuitClosure()); + run_loop.Run(); + } + + { + // Attempt to dispatch another message after the WeakPtr is invalidated. + base::Closure assert_not_reached = base::Bind([] { NOTREACHED(); }); + impl.set_ping_handler(assert_not_reached); + proxy->Ping(assert_not_reached); + + // The binding will close its end of the pipe which will trigger a + // connection error on |proxy|. + base::RunLoop run_loop; + proxy.set_connection_error_handler(run_loop.QuitClosure()); + weak_factory.InvalidateWeakPtrs(); + run_loop.Run(); + } +} + // StrongBindingTest ----------------------------------------------------------- using StrongBindingTest = BindingTestBase; @@ -320,43 +495,31 @@ TEST_F(StrongBindingTest, DestroyClosesMessagePipe) { base::RunLoop run_loop; bool encountered_error = false; bool was_deleted = false; - ServiceImpl impl(&was_deleted); sample::ServicePtr ptr; - auto request = GetProxy(&ptr); + auto request = MakeRequest(&ptr); ptr.set_connection_error_handler( SetFlagAndRunClosure(&encountered_error, run_loop.QuitClosure())); bool called = false; base::RunLoop run_loop2; - { - StrongBinding<sample::Service> binding(&impl, std::move(request)); - ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, - SetFlagAndRunClosure<int32_t>(&called, - run_loop2.QuitClosure())); - run_loop2.Run(); - EXPECT_TRUE(called); - EXPECT_FALSE(encountered_error); - } - // Now that the StrongBinding is out of scope we should detect an error on the - // other end of the pipe. - run_loop.Run(); - EXPECT_TRUE(encountered_error); - // But destroying the StrongBinding doesn't destroy the object. - ASSERT_FALSE(was_deleted); -} - -class ServiceImplWithStrongBinding : public ServiceImpl { - public: - ServiceImplWithStrongBinding(bool* was_deleted, - InterfaceRequest<sample::Service> request) - : ServiceImpl(was_deleted), binding_(this, std::move(request)) {} - StrongBinding<sample::Service>& binding() { return binding_; } + auto binding = MakeStrongBinding(base::MakeUnique<ServiceImpl>(&was_deleted), + std::move(request)); + ptr->Frobinate( + nullptr, sample::Service::BazOptions::REGULAR, nullptr, + SetFlagAndRunClosure<int32_t>(&called, run_loop2.QuitClosure())); + run_loop2.Run(); + EXPECT_TRUE(called); + EXPECT_FALSE(encountered_error); + binding->Close(); - private: - StrongBinding<sample::Service> binding_; + // Now that the StrongBinding is closed we should detect an error on the other + // end of the pipe. + run_loop.Run(); + EXPECT_TRUE(encountered_error); - DISALLOW_COPY_AND_ASSIGN(ServiceImplWithStrongBinding); -}; + // Destroying the StrongBinding also destroys the impl. + ASSERT_TRUE(was_deleted); +} // Tests the typical case, where the implementation object owns the // StrongBinding (and should be destroyed on connection error). @@ -366,7 +529,7 @@ TEST_F(StrongBindingTest, ConnectionErrorDestroysImpl) { // Will delete itself. base::RunLoop run_loop; new ServiceImplWithBinding(&was_deleted, run_loop.QuitClosure(), - GetProxy(&ptr)); + MakeRequest(&ptr)); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(was_deleted); @@ -377,37 +540,71 @@ TEST_F(StrongBindingTest, ConnectionErrorDestroysImpl) { EXPECT_TRUE(was_deleted); } -// Tests that even when the implementation object owns the StrongBinding, that -// the implementation can still be deleted (which should result in the message -// pipe being closed). Also checks that the connection error handler doesn't get -// called. -TEST_F(StrongBindingTest, ExplicitDeleteImpl) { - bool ptr_error_handler_called = false; - sample::ServicePtr ptr; - auto request = GetProxy(&ptr); - base::RunLoop run_loop; - ptr.set_connection_error_handler( - SetFlagAndRunClosure(&ptr_error_handler_called, run_loop.QuitClosure())); +TEST_F(StrongBindingTest, FlushForTesting) { + bool called = false; bool was_deleted = false; - ServiceImplWithStrongBinding* impl = - new ServiceImplWithStrongBinding(&was_deleted, std::move(request)); - bool binding_error_handler_called = false; - impl->binding().set_connection_error_handler( - SetFlagAndRunClosure(&binding_error_handler_called)); + sample::ServicePtr ptr; + auto request = MakeRequest(&ptr); + auto binding = MakeStrongBinding(base::MakeUnique<ServiceImpl>(&was_deleted), + std::move(request)); + binding->set_connection_error_handler(base::Bind(&Fail)); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(ptr_error_handler_called); + ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, + SetFlagAndRunClosure<int32_t>(&called)); + EXPECT_FALSE(called); + // Because the flush is sent from the binding, it only guarantees that the + // request has been received, not the response. The second flush waits for the + // response to be received. + ASSERT_TRUE(binding); + binding->FlushForTesting(); + ASSERT_TRUE(binding); + binding->FlushForTesting(); + EXPECT_TRUE(called); EXPECT_FALSE(was_deleted); - - delete impl; - EXPECT_FALSE(ptr_error_handler_called); + ptr.reset(); + ASSERT_TRUE(binding); + binding->set_connection_error_handler(base::Closure()); + binding->FlushForTesting(); EXPECT_TRUE(was_deleted); - was_deleted = false; // It shouldn't be double-deleted! - run_loop.Run(); - EXPECT_TRUE(ptr_error_handler_called); +} + +TEST_F(StrongBindingTest, FlushForTestingWithClosedPeer) { + bool called = false; + bool was_deleted = false; + sample::ServicePtr ptr; + auto request = MakeRequest(&ptr); + auto binding = MakeStrongBinding(base::MakeUnique<ServiceImpl>(&was_deleted), + std::move(request)); + binding->set_connection_error_handler(SetFlagAndRunClosure(&called)); + ptr.reset(); + + EXPECT_FALSE(called); EXPECT_FALSE(was_deleted); + ASSERT_TRUE(binding); + binding->FlushForTesting(); + EXPECT_TRUE(called); + EXPECT_TRUE(was_deleted); + ASSERT_FALSE(binding); +} - EXPECT_FALSE(binding_error_handler_called); +TEST_F(StrongBindingTest, ConnectionErrorWithReason) { + sample::ServicePtr ptr; + auto request = MakeRequest(&ptr); + auto binding = + MakeStrongBinding(base::MakeUnique<ServiceImpl>(), std::move(request)); + base::RunLoop run_loop; + binding->set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(5678u, custom_reason); + EXPECT_EQ("hello", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + ptr.ResetWithReason(5678u, "hello"); + + run_loop.Run(); } } // namespace diff --git a/mojo/public/cpp/bindings/tests/bindings_perftest.cc b/mojo/public/cpp/bindings/tests/bindings_perftest.cc index db0dd05..6a50de4 100644 --- a/mojo/public/cpp/bindings/tests/bindings_perftest.cc +++ b/mojo/public/cpp/bindings/tests/bindings_perftest.cc @@ -8,7 +8,13 @@ #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/interface_endpoint_client.h" +#include "mojo/public/cpp/bindings/lib/message_builder.h" +#include "mojo/public/cpp/bindings/lib/multiplex_router.h" +#include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/test_support/test_support.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h" @@ -81,9 +87,7 @@ void PingPongTest::OnPingDone() { } struct BoundPingService { - BoundPingService() : binding(&impl) { - binding.Bind(GetProxy(&service)); - } + BoundPingService() : binding(&impl) { binding.Bind(MakeRequest(&service)); } PingServiceImpl impl; test::PingServicePtr service; @@ -101,7 +105,7 @@ class MojoBindingsPerftest : public testing::Test { TEST_F(MojoBindingsPerftest, InProcessPingPong) { test::PingServicePtr service; PingServiceImpl impl; - Binding<test::PingService> binding(&impl, GetProxy(&service)); + Binding<test::PingService> binding(&impl, MakeRequest(&service)); PingPongTest test(std::move(service)); { @@ -133,5 +137,148 @@ TEST_F(MojoBindingsPerftest, InProcessPingPong) { } } +class PingPongPaddle : public MessageReceiverWithResponderStatus { + public: + PingPongPaddle(MessageReceiver* sender) : sender_(sender) {} + + void set_sender(MessageReceiver* sender) { sender_ = sender; } + + bool Accept(Message* message) override { + uint32_t count = message->header()->name; + if (!quit_closure_.is_null()) { + count++; + if (count >= expected_count_) { + end_time_ = base::TimeTicks::Now(); + quit_closure_.Run(); + return true; + } + } + + internal::MessageBuilder builder(count, 0, 8, 0); + bool result = sender_->Accept(builder.message()); + DCHECK(result); + return true; + } + + bool AcceptWithResponder(Message* message, + MessageReceiverWithStatus* responder) override { + NOTREACHED(); + return true; + } + + base::TimeDelta Serve(uint32_t expected_count) { + base::RunLoop run_loop; + + expected_count_ = expected_count; + quit_closure_ = run_loop.QuitClosure(); + + start_time_ = base::TimeTicks::Now(); + internal::MessageBuilder builder(0, 0, 8, 0); + bool result = sender_->Accept(builder.message()); + DCHECK(result); + + run_loop.Run(); + + return end_time_ - start_time_; + } + + private: + base::TimeTicks start_time_; + base::TimeTicks end_time_; + uint32_t expected_count_ = 0; + MessageReceiver* sender_; + base::Closure quit_closure_; +}; + +TEST_F(MojoBindingsPerftest, MultiplexRouterPingPong) { + MessagePipe pipe; + scoped_refptr<internal::MultiplexRouter> router0( + new internal::MultiplexRouter(std::move(pipe.handle0), + internal::MultiplexRouter::SINGLE_INTERFACE, + true, base::ThreadTaskRunnerHandle::Get())); + scoped_refptr<internal::MultiplexRouter> router1( + new internal::MultiplexRouter( + std::move(pipe.handle1), internal::MultiplexRouter::SINGLE_INTERFACE, + false, base::ThreadTaskRunnerHandle::Get())); + + PingPongPaddle paddle0(nullptr); + PingPongPaddle paddle1(nullptr); + + InterfaceEndpointClient client0( + router0->CreateLocalEndpointHandle(kMasterInterfaceId), &paddle0, nullptr, + false, base::ThreadTaskRunnerHandle::Get(), 0u); + InterfaceEndpointClient client1( + router1->CreateLocalEndpointHandle(kMasterInterfaceId), &paddle1, nullptr, + false, base::ThreadTaskRunnerHandle::Get(), 0u); + + paddle0.set_sender(&client0); + paddle1.set_sender(&client1); + + static const uint32_t kWarmUpIterations = 1000; + static const uint32_t kTestIterations = 1000000; + + paddle0.Serve(kWarmUpIterations); + + base::TimeDelta duration = paddle0.Serve(kTestIterations); + + test::LogPerfResult("MultiplexRouterPingPong", nullptr, + kTestIterations / duration.InSecondsF(), "pings/second"); +} + +class CounterReceiver : public MessageReceiverWithResponderStatus { + public: + bool Accept(Message* message) override { + counter_++; + return true; + } + + bool AcceptWithResponder(Message* message, + MessageReceiverWithStatus* responder) override { + NOTREACHED(); + return true; + } + + uint32_t counter() const { return counter_; } + + void Reset() { counter_ = 0; } + + private: + uint32_t counter_ = 0; +}; + +TEST_F(MojoBindingsPerftest, MultiplexRouterDispatchCost) { + MessagePipe pipe; + scoped_refptr<internal::MultiplexRouter> router(new internal::MultiplexRouter( + std::move(pipe.handle0), internal::MultiplexRouter::SINGLE_INTERFACE, + true, base::ThreadTaskRunnerHandle::Get())); + CounterReceiver receiver; + InterfaceEndpointClient client( + router->CreateLocalEndpointHandle(kMasterInterfaceId), &receiver, nullptr, + false, base::ThreadTaskRunnerHandle::Get(), 0u); + + static const uint32_t kIterations[] = {1000, 3000000}; + + for (size_t i = 0; i < 2; ++i) { + receiver.Reset(); + base::TimeTicks start_time = base::TimeTicks::Now(); + for (size_t j = 0; j < kIterations[i]; ++j) { + internal::MessageBuilder builder(0, 0, 8, 0); + bool result = + router->SimulateReceivingMessageForTesting(builder.message()); + DCHECK(result); + } + + base::TimeTicks end_time = base::TimeTicks::Now(); + base::TimeDelta duration = end_time - start_time; + CHECK_EQ(kIterations[i], receiver.counter()); + + if (i == 1) { + test::LogPerfResult("MultiplexRouterDispatchCost", nullptr, + kIterations[i] / duration.InSecondsF(), + "times/second"); + } + } +} + } // namespace } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/connector_unittest.cc b/mojo/public/cpp/bindings/tests/connector_unittest.cc index 89cc51d..74ecb7a 100644 --- a/mojo/public/cpp/bindings/tests/connector_unittest.cc +++ b/mojo/public/cpp/bindings/tests/connector_unittest.cc @@ -14,6 +14,7 @@ #include "base/callback_helpers.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "mojo/public/cpp/bindings/lib/message_builder.h" #include "mojo/public/cpp/bindings/tests/message_queue.h" @@ -98,10 +99,10 @@ class ConnectorTest : public testing::Test { void AllocMessage(const char* text, Message* message) { size_t payload_size = strlen(text) + 1; // Plus null terminator. - internal::MessageBuilder builder(1, payload_size); + internal::MessageBuilder builder(1, 0, payload_size, 0); memcpy(builder.buffer()->Allocate(payload_size), text, payload_size); - builder.message()->MoveTo(message); + *message = std::move(*builder.message()); } protected: @@ -572,6 +573,27 @@ TEST_F(ConnectorTest, ProcessWhenNested) { ASSERT_EQ(2u, accumulator.size()); } +TEST_F(ConnectorTest, DestroyOnDifferentThreadAfterClose) { + std::unique_ptr<Connector> connector( + new Connector(std::move(handle0_), Connector::SINGLE_THREADED_SEND, + base::ThreadTaskRunnerHandle::Get())); + + connector->CloseMessagePipe(); + + base::Thread another_thread("ThreadForDestroyingConnector"); + another_thread.Start(); + + base::RunLoop run_loop; + another_thread.task_runner()->PostTaskAndReply( + FROM_HERE, + base::Bind( + [](std::unique_ptr<Connector> connector) { connector.reset(); }, + base::Passed(std::move(connector))), + run_loop.QuitClosure()); + + run_loop.Run(); +} + } // namespace } // namespace test } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/constant_unittest.cc b/mojo/public/cpp/bindings/tests/constant_unittest.cc index f6394f3..caa6464 100644 --- a/mojo/public/cpp/bindings/tests/constant_unittest.cc +++ b/mojo/public/cpp/bindings/tests/constant_unittest.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cmath> + +#include "base/strings/string_piece.h" #include "mojo/public/interfaces/bindings/tests/test_constants.mojom.h" #include "testing/gtest/include/gtest/gtest.h" @@ -19,23 +22,38 @@ TEST(ConstantTest, GlobalConstants) { static_assert(kUint32Value == 4294967295U, ""); static_assert(kInt64Value == -9223372036854775807, ""); static_assert(kUint64Value == 9999999999999999999ULL, ""); - - EXPECT_DOUBLE_EQ(kDoubleValue, 3.14159); - EXPECT_FLOAT_EQ(kFloatValue, 2.71828f); + static_assert(kDoubleValue == 3.14159, ""); + static_assert(kFloatValue == 2.71828f, ""); + + EXPECT_EQ(base::StringPiece(kStringValue), "test string contents"); + EXPECT_TRUE(std::isnan(kDoubleNaN)); + EXPECT_TRUE(std::isinf(kDoubleInfinity)); + EXPECT_TRUE(std::isinf(kDoubleNegativeInfinity)); + EXPECT_NE(kDoubleInfinity, kDoubleNegativeInfinity); + EXPECT_TRUE(std::isnan(kFloatNaN)); + EXPECT_TRUE(std::isinf(kFloatInfinity)); + EXPECT_TRUE(std::isinf(kFloatNegativeInfinity)); + EXPECT_NE(kFloatInfinity, kFloatNegativeInfinity); } TEST(ConstantTest, StructConstants) { // Compile-time constants. static_assert(StructWithConstants::kInt8Value == 5U, ""); + static_assert(StructWithConstants::kFloatValue == 765.432f, ""); - EXPECT_FLOAT_EQ(StructWithConstants::kFloatValue, 765.432f); + EXPECT_EQ(base::StringPiece(StructWithConstants::kStringValue), + "struct test string contents"); } TEST(ConstantTest, InterfaceConstants) { // Compile-time constants. static_assert(InterfaceWithConstants::kUint32Value == 20100722, ""); + static_assert(InterfaceWithConstants::kDoubleValue == 12.34567, ""); - EXPECT_DOUBLE_EQ(InterfaceWithConstants::kDoubleValue, 12.34567); + EXPECT_EQ(base::StringPiece(InterfaceWithConstants::kStringValue), + "interface test string contents"); + EXPECT_EQ(base::StringPiece(InterfaceWithConstants::Name_), + "mojo::test::InterfaceWithConstants"); } } // namespace test diff --git a/mojo/public/cpp/bindings/tests/data_view_unittest.cc b/mojo/public/cpp/bindings/tests/data_view_unittest.cc new file mode 100644 index 0000000..0ebfda5 --- /dev/null +++ b/mojo/public/cpp/bindings/tests/data_view_unittest.cc @@ -0,0 +1,303 @@ +// 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 <memory> +#include <string> +#include <unordered_map> +#include <vector> + +#include "base/message_loop/message_loop.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" +#include "mojo/public/cpp/bindings/lib/serialization.h" +#include "mojo/public/interfaces/bindings/tests/test_data_view.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace test { +namespace data_view { +namespace { + +class DataViewTest : public testing::Test { + private: + base::MessageLoop message_loop_; +}; + +struct DataViewHolder { + std::unique_ptr<TestStructDataView> data_view; + std::unique_ptr<mojo::internal::FixedBufferForTesting> buf; + mojo::internal::SerializationContext context; +}; + +std::unique_ptr<DataViewHolder> SerializeTestStruct(TestStructPtr input) { + std::unique_ptr<DataViewHolder> result(new DataViewHolder); + + size_t size = mojo::internal::PrepareToSerialize<TestStructDataView>( + input, &result->context); + + result->buf.reset(new mojo::internal::FixedBufferForTesting(size)); + internal::TestStruct_Data* data = nullptr; + mojo::internal::Serialize<TestStructDataView>(input, result->buf.get(), &data, + &result->context); + + result->data_view.reset(new TestStructDataView(data, &result->context)); + return result; +} + +class TestInterfaceImpl : public TestInterface { + public: + explicit TestInterfaceImpl(TestInterfaceRequest request) + : binding_(this, std::move(request)) {} + ~TestInterfaceImpl() override {} + + // TestInterface implementation: + void Echo(int32_t value, const EchoCallback& callback) override { + callback.Run(value); + } + + private: + Binding<TestInterface> binding_; +}; + +} // namespace + +TEST_F(DataViewTest, String) { + TestStructPtr obj(TestStruct::New()); + obj->f_string = "hello"; + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + StringDataView string_data_view; + data_view.GetFStringDataView(&string_data_view); + + ASSERT_FALSE(string_data_view.is_null()); + EXPECT_EQ(std::string("hello"), + std::string(string_data_view.storage(), string_data_view.size())); +} + +TEST_F(DataViewTest, NestedStruct) { + TestStructPtr obj(TestStruct::New()); + obj->f_struct = NestedStruct::New(); + obj->f_struct->f_int32 = 42; + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + NestedStructDataView struct_data_view; + data_view.GetFStructDataView(&struct_data_view); + + ASSERT_FALSE(struct_data_view.is_null()); + EXPECT_EQ(42, struct_data_view.f_int32()); +} + +TEST_F(DataViewTest, NativeStruct) { + TestStructPtr obj(TestStruct::New()); + obj->f_native_struct = NativeStruct::New(); + obj->f_native_struct->data = std::vector<uint8_t>({3, 2, 1}); + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + NativeStructDataView struct_data_view; + data_view.GetFNativeStructDataView(&struct_data_view); + + ASSERT_FALSE(struct_data_view.is_null()); + ASSERT_EQ(3u, struct_data_view.size()); + EXPECT_EQ(3, struct_data_view[0]); + EXPECT_EQ(2, struct_data_view[1]); + EXPECT_EQ(1, struct_data_view[2]); + EXPECT_EQ(3, *struct_data_view.data()); +} + +TEST_F(DataViewTest, BoolArray) { + TestStructPtr obj(TestStruct::New()); + obj->f_bool_array = {true, false}; + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + ArrayDataView<bool> array_data_view; + data_view.GetFBoolArrayDataView(&array_data_view); + + ASSERT_FALSE(array_data_view.is_null()); + ASSERT_EQ(2u, array_data_view.size()); + EXPECT_TRUE(array_data_view[0]); + EXPECT_FALSE(array_data_view[1]); +} + +TEST_F(DataViewTest, IntegerArray) { + TestStructPtr obj(TestStruct::New()); + obj->f_int32_array = {1024, 128}; + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + ArrayDataView<int32_t> array_data_view; + data_view.GetFInt32ArrayDataView(&array_data_view); + + ASSERT_FALSE(array_data_view.is_null()); + ASSERT_EQ(2u, array_data_view.size()); + EXPECT_EQ(1024, array_data_view[0]); + EXPECT_EQ(128, array_data_view[1]); + EXPECT_EQ(1024, *array_data_view.data()); +} + +TEST_F(DataViewTest, EnumArray) { + TestStructPtr obj(TestStruct::New()); + obj->f_enum_array = {TestEnum::VALUE_1, TestEnum::VALUE_0}; + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + ArrayDataView<TestEnum> array_data_view; + data_view.GetFEnumArrayDataView(&array_data_view); + + ASSERT_FALSE(array_data_view.is_null()); + ASSERT_EQ(2u, array_data_view.size()); + EXPECT_EQ(TestEnum::VALUE_1, array_data_view[0]); + EXPECT_EQ(TestEnum::VALUE_0, array_data_view[1]); + EXPECT_EQ(TestEnum::VALUE_0, *(array_data_view.data() + 1)); + + TestEnum output; + ASSERT_TRUE(array_data_view.Read(0, &output)); + EXPECT_EQ(TestEnum::VALUE_1, output); +} + +TEST_F(DataViewTest, InterfaceArray) { + TestInterfacePtr ptr; + TestInterfaceImpl impl(MakeRequest(&ptr)); + + TestStructPtr obj(TestStruct::New()); + obj->f_interface_array.push_back(std::move(ptr)); + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + ArrayDataView<TestInterfacePtrDataView> array_data_view; + data_view.GetFInterfaceArrayDataView(&array_data_view); + + ASSERT_FALSE(array_data_view.is_null()); + ASSERT_EQ(1u, array_data_view.size()); + + TestInterfacePtr ptr2 = array_data_view.Take<TestInterfacePtr>(0); + ASSERT_TRUE(ptr2); + int32_t result = 0; + ASSERT_TRUE(ptr2->Echo(42, &result)); + EXPECT_EQ(42, result); +} + +TEST_F(DataViewTest, NestedArray) { + TestStructPtr obj(TestStruct::New()); + obj->f_nested_array = {{3, 4}, {2}}; + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + ArrayDataView<ArrayDataView<int32_t>> array_data_view; + data_view.GetFNestedArrayDataView(&array_data_view); + + ASSERT_FALSE(array_data_view.is_null()); + ASSERT_EQ(2u, array_data_view.size()); + + ArrayDataView<int32_t> nested_array_data_view; + array_data_view.GetDataView(0, &nested_array_data_view); + ASSERT_FALSE(nested_array_data_view.is_null()); + ASSERT_EQ(2u, nested_array_data_view.size()); + EXPECT_EQ(4, nested_array_data_view[1]); + + std::vector<int32_t> vec; + ASSERT_TRUE(array_data_view.Read(1, &vec)); + ASSERT_EQ(1u, vec.size()); + EXPECT_EQ(2, vec[0]); +} + +TEST_F(DataViewTest, StructArray) { + NestedStructPtr nested_struct(NestedStruct::New()); + nested_struct->f_int32 = 42; + + TestStructPtr obj(TestStruct::New()); + obj->f_struct_array.push_back(std::move(nested_struct)); + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + ArrayDataView<NestedStructDataView> array_data_view; + data_view.GetFStructArrayDataView(&array_data_view); + + ASSERT_FALSE(array_data_view.is_null()); + ASSERT_EQ(1u, array_data_view.size()); + + NestedStructDataView struct_data_view; + array_data_view.GetDataView(0, &struct_data_view); + ASSERT_FALSE(struct_data_view.is_null()); + EXPECT_EQ(42, struct_data_view.f_int32()); + + NestedStructPtr nested_struct2; + ASSERT_TRUE(array_data_view.Read(0, &nested_struct2)); + ASSERT_TRUE(nested_struct2); + EXPECT_EQ(42, nested_struct2->f_int32); +} + +TEST_F(DataViewTest, Map) { + TestStructPtr obj(TestStruct::New()); + obj->f_map["1"] = 1; + obj->f_map["2"] = 2; + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + MapDataView<StringDataView, int32_t> map_data_view; + data_view.GetFMapDataView(&map_data_view); + + ASSERT_FALSE(map_data_view.is_null()); + ASSERT_EQ(2u, map_data_view.size()); + + ASSERT_FALSE(map_data_view.keys().is_null()); + ASSERT_EQ(2u, map_data_view.keys().size()); + + ASSERT_FALSE(map_data_view.values().is_null()); + ASSERT_EQ(2u, map_data_view.values().size()); + + std::vector<std::string> keys; + ASSERT_TRUE(map_data_view.ReadKeys(&keys)); + std::vector<int32_t> values; + ASSERT_TRUE(map_data_view.ReadValues(&values)); + + std::unordered_map<std::string, int32_t> map; + for (size_t i = 0; i < 2; ++i) + map[keys[i]] = values[i]; + + EXPECT_EQ(1, map["1"]); + EXPECT_EQ(2, map["2"]); +} + +TEST_F(DataViewTest, UnionArray) { + TestUnionPtr union_ptr(TestUnion::New()); + union_ptr->set_f_int32(1024); + + TestStructPtr obj(TestStruct::New()); + obj->f_union_array.push_back(std::move(union_ptr)); + + auto data_view_holder = SerializeTestStruct(std::move(obj)); + auto& data_view = *data_view_holder->data_view; + + ArrayDataView<TestUnionDataView> array_data_view; + data_view.GetFUnionArrayDataView(&array_data_view); + ASSERT_FALSE(array_data_view.is_null()); + ASSERT_EQ(1u, array_data_view.size()); + + TestUnionDataView union_data_view; + array_data_view.GetDataView(0, &union_data_view); + ASSERT_FALSE(union_data_view.is_null()); + + TestUnionPtr union_ptr2; + ASSERT_TRUE(array_data_view.Read(0, &union_ptr2)); + ASSERT_TRUE(union_ptr2->is_f_int32()); + EXPECT_EQ(1024, union_ptr2->get_f_int32()); +} + +} // namespace data_view +} // namespace test +} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/e2e_perftest.cc b/mojo/public/cpp/bindings/tests/e2e_perftest.cc index 66ac6dc..bc69e0f 100644 --- a/mojo/public/cpp/bindings/tests/e2e_perftest.cc +++ b/mojo/public/cpp/bindings/tests/e2e_perftest.cc @@ -7,13 +7,14 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/test/perf_time_logger.h" #include "base/threading/thread_task_runner_handle.h" +#include "mojo/edk/embedder/embedder.h" #include "mojo/edk/test/mojo_test_base.h" -#include "mojo/edk/test/scoped_ipc_support.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h" #include "testing/gtest/include/gtest/gtest.h" @@ -23,8 +24,7 @@ namespace { class EchoServiceImpl : public test::EchoService { public: - EchoServiceImpl(InterfaceRequest<EchoService> request, - const base::Closure& quit_closure); + explicit EchoServiceImpl(const base::Closure& quit_closure); ~EchoServiceImpl() override; // |EchoService| methods: @@ -32,13 +32,11 @@ class EchoServiceImpl : public test::EchoService { const EchoCallback& callback) override; private: - const StrongBinding<EchoService> binding_; const base::Closure quit_closure_; }; -EchoServiceImpl::EchoServiceImpl(InterfaceRequest<EchoService> request, - const base::Closure& quit_closure) - : binding_(this, std::move(request)), quit_closure_(quit_closure) {} +EchoServiceImpl::EchoServiceImpl(const base::Closure& quit_closure) + : quit_closure_(quit_closure) {} EchoServiceImpl::~EchoServiceImpl() { quit_closure_.Run(); @@ -163,7 +161,7 @@ class MojoE2EPerftest : public edk::test::MojoTestBase { void CreateAndRunService(InterfaceRequest<test::EchoService> request, const base::Closure& cb) { - new EchoServiceImpl(std::move(request), cb); + MakeStrongBinding(base::MakeUnique<EchoServiceImpl>(cb), std::move(request)); } DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingService, MojoE2EPerftest, mp) { @@ -173,7 +171,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingService, MojoE2EPerftest, mp) { InterfaceRequest<test::EchoService> request; request.Bind(ScopedMessagePipeHandle(MessagePipeHandle(service_mp))); base::RunLoop run_loop; - edk::test::GetIoTaskRunner()->PostTask( + edk::GetIOTaskRunner()->PostTask( FROM_HERE, base::Bind(&CreateAndRunService, base::Passed(&request), base::Bind(base::IgnoreResult(&base::TaskRunner::PostTask), @@ -197,7 +195,7 @@ TEST_F(MojoE2EPerftest, MultiProcessEchoIoThread) { MojoHandle client_mp, service_mp; CreateMessagePipe(&client_mp, &service_mp); WriteMessageWithHandles(mp, "hello", &service_mp, 1); - RunTestOnTaskRunner(edk::test::GetIoTaskRunner(), client_mp, + RunTestOnTaskRunner(edk::GetIOTaskRunner().get(), client_mp, "MultiProcessEchoIoThread"); END_CHILD() } diff --git a/mojo/public/cpp/bindings/tests/equals_unittest.cc b/mojo/public/cpp/bindings/tests/equals_unittest.cc index 376c2bd..6483baf 100644 --- a/mojo/public/cpp/bindings/tests/equals_unittest.cc +++ b/mojo/public/cpp/bindings/tests/equals_unittest.cc @@ -14,12 +14,7 @@ namespace test { namespace { RectPtr CreateRect() { - RectPtr r = Rect::New(); - r->x = 1; - r->y = 2; - r->width = 3; - r->height = 4; - return r; + return Rect::New(1, 2, 3, 4); } using EqualsTest = testing::Test; @@ -48,9 +43,7 @@ TEST_F(EqualsTest, Struct) { } TEST_F(EqualsTest, StructNested) { - RectPairPtr p1(RectPair::New()); - p1->first = CreateRect(); - p1->second = CreateRect(); + RectPairPtr p1(RectPair::New(CreateRect(), CreateRect())); RectPairPtr p2(p1.Clone()); EXPECT_TRUE(p1.Equals(p2)); p2->second->width = 0; @@ -60,10 +53,9 @@ TEST_F(EqualsTest, StructNested) { } TEST_F(EqualsTest, Array) { - NamedRegionPtr n1(NamedRegion::New()); - n1->name.emplace("n1"); - n1->rects.emplace(); - n1->rects->push_back(CreateRect()); + std::vector<RectPtr> rects; + rects.push_back(CreateRect()); + NamedRegionPtr n1(NamedRegion::New(std::string("n1"), std::move(rects))); NamedRegionPtr n2(n1.Clone()); EXPECT_TRUE(n1.Equals(n2)); @@ -84,37 +76,6 @@ TEST_F(EqualsTest, Array) { EXPECT_TRUE(n1.Equals(n2)); } -TEST_F(EqualsTest, Map) { - auto n1(NamedRegion::New()); - n1->name.emplace("foo"); - n1->rects.emplace(); - n1->rects->push_back(CreateRect()); - - Map<std::string, NamedRegionPtr> m1; - m1.insert("foo", std::move(n1)); - - decltype(m1) m2; - EXPECT_FALSE(m1.Equals(m2)); - - m2.insert("bar", m1.at("foo").Clone()); - EXPECT_FALSE(m1.Equals(m2)); - - m2 = m1.Clone(); - m2.at("foo")->name.emplace("monkey"); - EXPECT_FALSE(m1.Equals(m2)); - - m2 = m1.Clone(); - m2.at("foo")->rects->push_back(Rect::New()); - EXPECT_FALSE(m1.Equals(m2)); - - m2.at("foo")->rects->resize(1); - (*m2.at("foo")->rects)[0]->width = 1; - EXPECT_FALSE(m1.Equals(m2)); - - m2 = m1.Clone(); - EXPECT_TRUE(m1.Equals(m2)); -} - TEST_F(EqualsTest, InterfacePtr) { base::MessageLoop message_loop; @@ -124,13 +85,13 @@ TEST_F(EqualsTest, InterfacePtr) { EXPECT_TRUE(inf1.Equals(inf1)); EXPECT_TRUE(inf1.Equals(inf2)); - auto inf1_request = GetProxy(&inf1); + auto inf1_request = MakeRequest(&inf1); ALLOW_UNUSED_LOCAL(inf1_request); EXPECT_TRUE(inf1.Equals(inf1)); EXPECT_FALSE(inf1.Equals(inf2)); - auto inf2_request = GetProxy(&inf2); + auto inf2_request = MakeRequest(&inf2); ALLOW_UNUSED_LOCAL(inf2_request); EXPECT_FALSE(inf1.Equals(inf2)); @@ -146,13 +107,13 @@ TEST_F(EqualsTest, InterfaceRequest) { EXPECT_TRUE(req1.Equals(req2)); SomeInterfacePtr inf1; - req1 = GetProxy(&inf1); + req1 = MakeRequest(&inf1); EXPECT_TRUE(req1.Equals(req1)); EXPECT_FALSE(req1.Equals(req2)); SomeInterfacePtr inf2; - req2 = GetProxy(&inf2); + req2 = MakeRequest(&inf2); EXPECT_FALSE(req1.Equals(req2)); } diff --git a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc index 0bd9b28..6797fe4 100644 --- a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc +++ b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc @@ -5,6 +5,7 @@ #include <stdint.h> #include <utility> +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "mojo/public/cpp/bindings/binding.h" @@ -56,8 +57,8 @@ int ImportedInterfaceImpl::do_something_count_ = 0; class SampleNamedObjectImpl : public sample::NamedObject { public: - explicit SampleNamedObjectImpl(InterfaceRequest<sample::NamedObject> request) - : binding_(this, std::move(request)) {} + SampleNamedObjectImpl() {} + void SetName(const std::string& name) override { name_ = name; } void GetName(const GetNameCallback& callback) override { @@ -66,7 +67,6 @@ class SampleNamedObjectImpl : public sample::NamedObject { private: std::string name_; - StrongBinding<sample::NamedObject> binding_; }; class SampleFactoryImpl : public sample::Factory { @@ -95,9 +95,7 @@ class SampleFactoryImpl : public sample::Factory { EXPECT_TRUE(WriteTextMessage(pipe1_.get(), text2)); } - sample::ResponsePtr response(sample::Response::New()); - response->x = 2; - response->pipe = std::move(pipe0); + sample::ResponsePtr response(sample::Response::New(2, std::move(pipe0))); callback.Run(std::move(response), text1); if (request->obj) @@ -115,7 +113,7 @@ class SampleFactoryImpl : public sample::Factory { ASSERT_EQ(MOJO_RESULT_OK, MojoWait(pipe.get().value(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, &state)); - ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, state.satisfied_signals); + ASSERT_TRUE(state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); ASSERT_EQ(MOJO_RESULT_OK, ReadDataRaw( pipe.get(), nullptr, &data_size, MOJO_READ_DATA_FLAG_QUERY)); @@ -133,7 +131,8 @@ class SampleFactoryImpl : public sample::Factory { void CreateNamedObject( InterfaceRequest<sample::NamedObject> object_request) override { EXPECT_TRUE(object_request.is_pending()); - new SampleNamedObjectImpl(std::move(object_request)); + MakeStrongBinding(base::MakeUnique<SampleNamedObjectImpl>(), + std::move(object_request)); } // These aren't called or implemented, but exist here to test that the @@ -200,7 +199,7 @@ void DoStuff2(bool* got_response, TEST_F(HandlePassingTest, Basic) { sample::FactoryPtr factory; - SampleFactoryImpl factory_impl(GetProxy(&factory)); + SampleFactoryImpl factory_impl(MakeRequest(&factory)); MessagePipe pipe0; EXPECT_TRUE(WriteTextMessage(pipe0.handle1.get(), kText1)); @@ -210,13 +209,11 @@ TEST_F(HandlePassingTest, Basic) { imported::ImportedInterfacePtr imported; base::RunLoop run_loop; - ImportedInterfaceImpl imported_impl(GetProxy(&imported), + ImportedInterfaceImpl imported_impl(MakeRequest(&imported), run_loop.QuitClosure()); - sample::RequestPtr request(sample::Request::New()); - request->x = 1; - request->pipe = std::move(pipe1.handle0); - request->obj = std::move(imported); + sample::RequestPtr request(sample::Request::New( + 1, std::move(pipe1.handle0), base::nullopt, std::move(imported))); bool got_response = false; std::string got_text_reply; base::RunLoop run_loop2; @@ -237,10 +234,11 @@ TEST_F(HandlePassingTest, Basic) { TEST_F(HandlePassingTest, PassInvalid) { sample::FactoryPtr factory; - SampleFactoryImpl factory_impl(GetProxy(&factory)); + SampleFactoryImpl factory_impl(MakeRequest(&factory)); - sample::RequestPtr request(sample::Request::New()); - request->x = 1; + sample::RequestPtr request( + sample::Request::New(1, ScopedMessagePipeHandle(), base::nullopt, + imported::ImportedInterfacePtr())); bool got_response = false; std::string got_text_reply; base::RunLoop run_loop; @@ -258,7 +256,7 @@ TEST_F(HandlePassingTest, PassInvalid) { // Verifies DataPipeConsumer can be passed and read from. TEST_F(HandlePassingTest, DataPipe) { sample::FactoryPtr factory; - SampleFactoryImpl factory_impl(GetProxy(&factory)); + SampleFactoryImpl factory_impl(MakeRequest(&factory)); // Writes a string to a data pipe and passes the data pipe (consumer) to the // factory. @@ -296,7 +294,7 @@ TEST_F(HandlePassingTest, DataPipe) { TEST_F(HandlePassingTest, PipesAreClosed) { sample::FactoryPtr factory; - SampleFactoryImpl factory_impl(GetProxy(&factory)); + SampleFactoryImpl factory_impl(MakeRequest(&factory)); MessagePipe extra_pipe; @@ -322,12 +320,12 @@ TEST_F(HandlePassingTest, PipesAreClosed) { TEST_F(HandlePassingTest, CreateNamedObject) { sample::FactoryPtr factory; - SampleFactoryImpl factory_impl(GetProxy(&factory)); + SampleFactoryImpl factory_impl(MakeRequest(&factory)); sample::NamedObjectPtr object1; EXPECT_FALSE(object1); - InterfaceRequest<sample::NamedObject> object1_request = GetProxy(&object1); + InterfaceRequest<sample::NamedObject> object1_request(&object1); EXPECT_TRUE(object1_request.is_pending()); factory->CreateNamedObject(std::move(object1_request)); EXPECT_FALSE(object1_request.is_pending()); // We've passed the request. @@ -336,7 +334,7 @@ TEST_F(HandlePassingTest, CreateNamedObject) { object1->SetName("object1"); sample::NamedObjectPtr object2; - factory->CreateNamedObject(GetProxy(&object2)); + factory->CreateNamedObject(MakeRequest(&object2)); object2->SetName("object2"); base::RunLoop run_loop, run_loop2; diff --git a/mojo/public/cpp/bindings/tests/hash_unittest.cc b/mojo/public/cpp/bindings/tests/hash_unittest.cc new file mode 100644 index 0000000..9ce1f5b --- /dev/null +++ b/mojo/public/cpp/bindings/tests/hash_unittest.cc @@ -0,0 +1,35 @@ +// 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 "mojo/public/cpp/bindings/lib/hash_util.h" + +#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace test { +namespace { + +using HashTest = testing::Test; + +TEST_F(HashTest, NestedStruct) { + // Just check that this template instantiation compiles. + ASSERT_EQ( + ::mojo::internal::Hash(::mojo::internal::kHashSeed, + SimpleNestedStruct::New(ContainsOther::New(1))), + ::mojo::internal::Hash(::mojo::internal::kHashSeed, + SimpleNestedStruct::New(ContainsOther::New(1)))); +} + +TEST_F(HashTest, UnmappedNativeStruct) { + // Just check that this template instantiation compiles. + ASSERT_EQ(::mojo::internal::Hash(::mojo::internal::kHashSeed, + UnmappedNativeStruct::New()), + ::mojo::internal::Hash(::mojo::internal::kHashSeed, + UnmappedNativeStruct::New())); +} + +} // namespace +} // namespace test +} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc index aff6251..431a844 100644 --- a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc +++ b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc @@ -7,10 +7,14 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "base/threading/thread.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h" #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" #include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h" #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h" @@ -29,10 +33,6 @@ class MathCalculatorImpl : public math::Calculator { : total_(0.0), binding_(this, std::move(request)) {} ~MathCalculatorImpl() override {} - void CloseMessagePipe() { binding_.Close(); } - - void WaitForIncomingMethodCall() { binding_.WaitForIncomingMethodCall(); } - void Clear(const CalcCallback& callback) override { total_ = 0.0; callback.Run(total_); @@ -48,6 +48,8 @@ class MathCalculatorImpl : public math::Calculator { callback.Run(total_); } + Binding<math::Calculator>* binding() { return &binding_; } + private: double total_; Binding<math::Calculator> binding_; @@ -78,6 +80,8 @@ class MathCalculatorUI { double GetOutput() const { return output_; } + math::CalculatorPtr& GetInterfacePtr() { return calculator_; } + private: void Output(const base::Closure& closure, double output) { output_ = output; @@ -218,13 +222,13 @@ void ExpectValueAndRunClosure(uint32_t expected_value, TEST_F(InterfacePtrTest, IsBound) { math::CalculatorPtr calc; EXPECT_FALSE(calc.is_bound()); - MathCalculatorImpl calc_impl(GetProxy(&calc)); + MathCalculatorImpl calc_impl(MakeRequest(&calc)); EXPECT_TRUE(calc.is_bound()); } TEST_F(InterfacePtrTest, EndToEnd) { math::CalculatorPtr calc; - MathCalculatorImpl calc_impl(GetProxy(&calc)); + MathCalculatorImpl calc_impl(MakeRequest(&calc)); // Suppose this is instantiated in a process that has pipe1_. MathCalculatorUI calculator_ui(std::move(calc)); @@ -240,7 +244,7 @@ TEST_F(InterfacePtrTest, EndToEnd) { TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { math::CalculatorPtr calc; - MathCalculatorImpl calc_impl(GetProxy(&calc)); + MathCalculatorImpl calc_impl(MakeRequest(&calc)); // Suppose this is instantiated in a process that has pipe1_. MathCalculatorUI calculator_ui(std::move(calc)); @@ -250,14 +254,14 @@ TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { base::RunLoop run_loop; calculator_ui.Add(2.0, run_loop.QuitClosure()); EXPECT_EQ(0.0, calculator_ui.GetOutput()); - calc_impl.WaitForIncomingMethodCall(); + calc_impl.binding()->WaitForIncomingMethodCall(); run_loop.Run(); EXPECT_EQ(2.0, calculator_ui.GetOutput()); base::RunLoop run_loop2; calculator_ui.Multiply(5.0, run_loop2.QuitClosure()); EXPECT_EQ(2.0, calculator_ui.GetOutput()); - calc_impl.WaitForIncomingMethodCall(); + calc_impl.binding()->WaitForIncomingMethodCall(); run_loop2.Run(); EXPECT_EQ(10.0, calculator_ui.GetOutput()); } @@ -265,7 +269,7 @@ TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { TEST_F(InterfacePtrTest, Movable) { math::CalculatorPtr a; math::CalculatorPtr b; - MathCalculatorImpl calc_impl(GetProxy(&b)); + MathCalculatorImpl calc_impl(MakeRequest(&b)); EXPECT_TRUE(!a); EXPECT_FALSE(!b); @@ -312,7 +316,7 @@ TEST_F(InterfacePtrTest, BindInvalidHandle) { TEST_F(InterfacePtrTest, EncounteredError) { math::CalculatorPtr proxy; - MathCalculatorImpl calc_impl(GetProxy(&proxy)); + MathCalculatorImpl calc_impl(MakeRequest(&proxy)); MathCalculatorUI calculator_ui(std::move(proxy)); @@ -326,7 +330,7 @@ TEST_F(InterfacePtrTest, EncounteredError) { EXPECT_FALSE(calculator_ui.encountered_error()); // Close the server. - calc_impl.CloseMessagePipe(); + calc_impl.binding()->Close(); // The state change isn't picked up locally yet. base::RunLoop run_loop2; @@ -341,7 +345,7 @@ TEST_F(InterfacePtrTest, EncounteredError) { TEST_F(InterfacePtrTest, EncounteredErrorCallback) { math::CalculatorPtr proxy; - MathCalculatorImpl calc_impl(GetProxy(&proxy)); + MathCalculatorImpl calc_impl(MakeRequest(&proxy)); bool encountered_error = false; base::RunLoop run_loop; @@ -361,7 +365,7 @@ TEST_F(InterfacePtrTest, EncounteredErrorCallback) { EXPECT_FALSE(calculator_ui.encountered_error()); // Close the server. - calc_impl.CloseMessagePipe(); + calc_impl.binding()->Close(); // The state change isn't picked up locally yet. EXPECT_FALSE(calculator_ui.encountered_error()); @@ -378,7 +382,7 @@ TEST_F(InterfacePtrTest, EncounteredErrorCallback) { TEST_F(InterfacePtrTest, DestroyInterfacePtrOnMethodResponse) { math::CalculatorPtr proxy; - MathCalculatorImpl calc_impl(GetProxy(&proxy)); + MathCalculatorImpl calc_impl(MakeRequest(&proxy)); EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); @@ -393,7 +397,7 @@ TEST_F(InterfacePtrTest, DestroyInterfacePtrOnMethodResponse) { TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnMethodResponse) { math::CalculatorPtr proxy; - MathCalculatorImpl calc_impl(GetProxy(&proxy)); + MathCalculatorImpl calc_impl(MakeRequest(&proxy)); EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); @@ -408,7 +412,7 @@ TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnMethodResponse) { TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) { sample::ServicePtr proxy; - ReentrantServiceImpl impl(GetProxy(&proxy)); + ReentrantServiceImpl impl(MakeRequest(&proxy)); base::RunLoop run_loop, run_loop2; proxy->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, @@ -427,7 +431,7 @@ TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) { TEST_F(InterfacePtrTest, QueryVersion) { IntegerAccessorImpl impl; sample::IntegerAccessorPtr ptr; - Binding<sample::IntegerAccessor> binding(&impl, GetProxy(&ptr)); + Binding<sample::IntegerAccessor> binding(&impl, MakeRequest(&ptr)); EXPECT_EQ(0u, ptr.version()); @@ -442,7 +446,7 @@ TEST_F(InterfacePtrTest, QueryVersion) { TEST_F(InterfacePtrTest, RequireVersion) { IntegerAccessorImpl impl; sample::IntegerAccessorPtr ptr; - Binding<sample::IntegerAccessor> binding(&impl, GetProxy(&ptr)); + Binding<sample::IntegerAccessor> binding(&impl, MakeRequest(&ptr)); EXPECT_EQ(0u, ptr.version()); @@ -479,17 +483,7 @@ TEST_F(InterfacePtrTest, RequireVersion) { class StrongMathCalculatorImpl : public math::Calculator { public: - StrongMathCalculatorImpl(ScopedMessagePipeHandle handle, - bool* error_received, - bool* destroyed, - const base::Closure& closure) - : error_received_(error_received), - destroyed_(destroyed), - closure_(closure), - binding_(this, std::move(handle)) { - binding_.set_connection_error_handler( - base::Bind(&SetFlagAndRunClosure, error_received_, closure_)); - } + StrongMathCalculatorImpl(bool* destroyed) : destroyed_(destroyed) {} ~StrongMathCalculatorImpl() override { *destroyed_ = true; } // math::Calculator implementation. @@ -507,11 +501,7 @@ class StrongMathCalculatorImpl : public math::Calculator { private: double total_ = 0.0; - bool* error_received_; bool* destroyed_; - base::Closure closure_; - - StrongBinding<math::Calculator> binding_; }; TEST(StrongConnectorTest, Math) { @@ -519,13 +509,14 @@ TEST(StrongConnectorTest, Math) { bool error_received = false; bool destroyed = false; - MessagePipe pipe; + math::CalculatorPtr calc; base::RunLoop run_loop; - new StrongMathCalculatorImpl(std::move(pipe.handle0), &error_received, - &destroyed, run_loop.QuitClosure()); - math::CalculatorPtr calc; - calc.Bind(InterfacePtrInfo<math::Calculator>(std::move(pipe.handle1), 0u)); + auto binding = + MakeStrongBinding(base::MakeUnique<StrongMathCalculatorImpl>(&destroyed), + MakeRequest(&calc)); + binding->set_connection_error_handler(base::Bind( + &SetFlagAndRunClosure, &error_received, run_loop.QuitClosure())); { // Suppose this is instantiated in a process that has the other end of the @@ -626,10 +617,8 @@ TEST(WeakConnectorTest, Math) { class CImpl : public C { public: - CImpl(bool* d_called, InterfaceRequest<C> request, - const base::Closure& closure) - : d_called_(d_called), binding_(this, std::move(request)), - closure_(closure) {} + CImpl(bool* d_called, const base::Closure& closure) + : d_called_(d_called), closure_(closure) {} ~CImpl() override {} private: @@ -639,25 +628,22 @@ class CImpl : public C { } bool* d_called_; - StrongBinding<C> binding_; base::Closure closure_; }; class BImpl : public B { public: - BImpl(bool* d_called, InterfaceRequest<B> request, - const base::Closure& closure) - : d_called_(d_called), binding_(this, std::move(request)), - closure_(closure) {} + BImpl(bool* d_called, const base::Closure& closure) + : d_called_(d_called), closure_(closure) {} ~BImpl() override {} private: void GetC(InterfaceRequest<C> c) override { - new CImpl(d_called_, std::move(c), closure_); + MakeStrongBinding(base::MakeUnique<CImpl>(d_called_, closure_), + std::move(c)); } bool* d_called_; - StrongBinding<B> binding_; base::Closure closure_; }; @@ -672,7 +658,8 @@ class AImpl : public A { private: void GetB(InterfaceRequest<B> b) override { - new BImpl(&d_called_, std::move(b), closure_); + MakeStrongBinding(base::MakeUnique<BImpl>(&d_called_, closure_), + std::move(b)); } bool d_called_; @@ -683,15 +670,15 @@ class AImpl : public A { TEST_F(InterfacePtrTest, Scoping) { APtr a; base::RunLoop run_loop; - AImpl a_impl(GetProxy(&a), run_loop.QuitClosure()); + AImpl a_impl(MakeRequest(&a), run_loop.QuitClosure()); EXPECT_FALSE(a_impl.d_called()); { BPtr b; - a->GetB(GetProxy(&b)); + a->GetB(MakeRequest(&b)); CPtr c; - b->GetC(GetProxy(&c)); + b->GetC(MakeRequest(&c)); c->D(); } @@ -718,11 +705,11 @@ class PingTestImpl : public sample::PingTest { // Tests that FuseProxy does what it's supposed to do. TEST_F(InterfacePtrTest, Fusion) { sample::PingTestPtr proxy; - PingTestImpl impl(GetProxy(&proxy)); + PingTestImpl impl(MakeRequest(&proxy)); // Create another PingTest pipe. sample::PingTestPtr ptr; - sample::PingTestRequest request = GetProxy(&ptr); + sample::PingTestRequest request(&ptr); // Fuse the new pipe to the one hanging off |impl|. EXPECT_TRUE(FuseInterface(std::move(request), proxy.PassInterface())); @@ -735,6 +722,216 @@ TEST_F(InterfacePtrTest, Fusion) { EXPECT_TRUE(called); } +void Fail() { + FAIL() << "Unexpected connection error"; +} + +TEST_F(InterfacePtrTest, FlushForTesting) { + math::CalculatorPtr calc; + MathCalculatorImpl calc_impl(MakeRequest(&calc)); + calc.set_connection_error_handler(base::Bind(&Fail)); + + MathCalculatorUI calculator_ui(std::move(calc)); + + calculator_ui.Add(2.0, base::Bind(&base::DoNothing)); + calculator_ui.GetInterfacePtr().FlushForTesting(); + EXPECT_EQ(2.0, calculator_ui.GetOutput()); + + calculator_ui.Multiply(5.0, base::Bind(&base::DoNothing)); + calculator_ui.GetInterfacePtr().FlushForTesting(); + + EXPECT_EQ(10.0, calculator_ui.GetOutput()); +} + +void SetBool(bool* value) { + *value = true; +} + +TEST_F(InterfacePtrTest, FlushForTestingWithClosedPeer) { + math::CalculatorPtr calc; + MakeRequest(&calc); + bool called = false; + calc.set_connection_error_handler(base::Bind(&SetBool, &called)); + calc.FlushForTesting(); + EXPECT_TRUE(called); + calc.FlushForTesting(); +} + +TEST_F(InterfacePtrTest, ConnectionErrorWithReason) { + math::CalculatorPtr calc; + MathCalculatorImpl calc_impl(MakeRequest(&calc)); + + base::RunLoop run_loop; + calc.set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(42u, custom_reason); + EXPECT_EQ("hey", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + calc_impl.binding()->CloseWithReason(42u, "hey"); + + run_loop.Run(); +} + +TEST_F(InterfacePtrTest, InterfaceRequestResetWithReason) { + math::CalculatorPtr calc; + auto request = MakeRequest(&calc); + + base::RunLoop run_loop; + calc.set_connection_error_with_reason_handler(base::Bind( + [](const base::Closure& quit_closure, uint32_t custom_reason, + const std::string& description) { + EXPECT_EQ(88u, custom_reason); + EXPECT_EQ("greetings", description); + quit_closure.Run(); + }, + run_loop.QuitClosure())); + + request.ResetWithReason(88u, "greetings"); + + run_loop.Run(); +} + +TEST_F(InterfacePtrTest, CallbackIsPassedInterfacePtr) { + sample::PingTestPtr ptr; + sample::PingTestRequest request(&ptr); + + base::RunLoop run_loop; + + // Make a call with the proxy's lifetime bound to the response callback. + sample::PingTest* raw_proxy = ptr.get(); + ptr.set_connection_error_handler(run_loop.QuitClosure()); + raw_proxy->Ping( + base::Bind([](sample::PingTestPtr ptr) {}, base::Passed(&ptr))); + + // Trigger an error on |ptr|. This will ultimately lead to the proxy's + // response callbacks being destroyed, which will in turn lead to the proxy + // being destroyed. This should not crash. + request.PassMessagePipe(); + run_loop.Run(); +} + +TEST_F(InterfacePtrTest, ConnectionErrorHandlerOwnsInterfacePtr) { + sample::PingTestPtr* ptr = new sample::PingTestPtr; + sample::PingTestRequest request(ptr); + + base::RunLoop run_loop; + + // Make a call with |ptr|'s lifetime bound to the connection error handler + // callback. + ptr->set_connection_error_handler(base::Bind( + [](const base::Closure& quit, sample::PingTestPtr* ptr) { + ptr->reset(); + quit.Run(); + }, + run_loop.QuitClosure(), base::Owned(ptr))); + + // Trigger an error on |ptr|. In the error handler |ptr| is reset. This + // shouldn't immediately destroy the callback (and |ptr| that it owns), before + // the callback is completed. + request.PassMessagePipe(); + run_loop.Run(); +} + +TEST_F(InterfacePtrTest, ThreadSafeInterfacePointer) { + math::CalculatorPtr ptr; + MathCalculatorImpl calc_impl(MakeRequest(&ptr)); + scoped_refptr<math::ThreadSafeCalculatorPtr> thread_safe_ptr = + math::ThreadSafeCalculatorPtr::Create(std::move(ptr)); + + base::RunLoop run_loop; + + // Create and start the thread from where we'll call the interface pointer. + base::Thread other_thread("service test thread"); + other_thread.Start(); + + auto run_method = base::Bind( + [](const scoped_refptr<base::TaskRunner>& main_task_runner, + const base::Closure& quit_closure, + const scoped_refptr<math::ThreadSafeCalculatorPtr>& thread_safe_ptr) { + auto calc_callback = base::Bind( + [](const scoped_refptr<base::TaskRunner>& main_task_runner, + const base::Closure& quit_closure, + base::PlatformThreadId thread_id, + double result) { + EXPECT_EQ(123, result); + // Validate the callback is invoked on the calling thread. + EXPECT_EQ(thread_id, base::PlatformThread::CurrentId()); + // Notify the run_loop to quit. + main_task_runner->PostTask(FROM_HERE, quit_closure); + }); + (*thread_safe_ptr)->Add( + 123, base::Bind(calc_callback, main_task_runner, quit_closure, + base::PlatformThread::CurrentId())); + }, + base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure(), + thread_safe_ptr); + other_thread.message_loop()->task_runner()->PostTask(FROM_HERE, run_method); + + // Block until the method callback is called on the background thread. + run_loop.Run(); +} + +TEST_F(InterfacePtrTest, ThreadSafeInterfacePointerWithTaskRunner) { + // Create and start the thread from where we'll bind the interface pointer. + base::Thread other_thread("service test thread"); + other_thread.Start(); + const scoped_refptr<base::SingleThreadTaskRunner>& other_thread_task_runner = + other_thread.message_loop()->task_runner(); + + math::CalculatorPtr ptr; + math::CalculatorRequest request(&ptr); + + // Create a ThreadSafeInterfacePtr that we'll bind from a different thread. + scoped_refptr<math::ThreadSafeCalculatorPtr> thread_safe_ptr = + math::ThreadSafeCalculatorPtr::Create(ptr.PassInterface(), + other_thread_task_runner); + ASSERT_TRUE(thread_safe_ptr); + + MathCalculatorImpl* math_calc_impl = nullptr; + { + base::RunLoop run_loop; + auto run_method = base::Bind( + [](const scoped_refptr<base::TaskRunner>& main_task_runner, + const base::Closure& quit_closure, + const scoped_refptr<math::ThreadSafeCalculatorPtr>& thread_safe_ptr, + math::CalculatorRequest request, + MathCalculatorImpl** math_calc_impl) { + math::CalculatorPtr ptr; + // In real life, the implementation would have a legitimate owner. + *math_calc_impl = new MathCalculatorImpl(std::move(request)); + main_task_runner->PostTask(FROM_HERE, quit_closure); + }, + base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure(), + thread_safe_ptr, base::Passed(&request), &math_calc_impl); + other_thread.message_loop()->task_runner()->PostTask(FROM_HERE, run_method); + run_loop.Run(); + } + + { + // The interface ptr is bound, we can call methods on it. + auto calc_callback = + base::Bind([](const base::Closure& quit_closure, double result) { + EXPECT_EQ(123, result); + quit_closure.Run(); + }); + base::RunLoop run_loop; + (*thread_safe_ptr) + ->Add(123, base::Bind(calc_callback, run_loop.QuitClosure())); + // Block until the method callback is called. + run_loop.Run(); + } + + other_thread_task_runner->DeleteSoon(FROM_HERE, math_calc_impl); + + // Reset the pointer now so the InterfacePtr associated resources can be + // deleted before the background thread's message loop is invalidated. + thread_safe_ptr = nullptr; +} + } // namespace } // namespace test } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/map_common_test.h b/mojo/public/cpp/bindings/tests/map_common_test.h deleted file mode 100644 index c8654ce..0000000 --- a/mojo/public/cpp/bindings/tests/map_common_test.h +++ /dev/null @@ -1,230 +0,0 @@ -// 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 "mojo/public/cpp/bindings/array.h" -#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" -#include "mojo/public/cpp/bindings/lib/serialization.h" -#include "mojo/public/cpp/bindings/lib/validate_params.h" -#include "mojo/public/cpp/bindings/map.h" -#include "mojo/public/cpp/bindings/string.h" -#include "mojo/public/cpp/bindings/tests/container_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace WTF { -class String; -} - -namespace mojo { - -template <typename T> -class WTFArray; - -template <typename K, typename V> -class WTFMap; - -namespace test { -namespace { - -struct StringIntData { - const char* string_data; - int int_data; -} kStringIntData[] = { - {"one", 1}, - {"two", 2}, - {"three", 3}, - {"four", 4}, -}; - -const size_t kStringIntDataSize = 4; - -} // namespace - -template <template <typename...> class MapType> -struct TypeTraits; - -template <> -struct TypeTraits<Map> { - using StringType = mojo::String; - template <typename T> - using ArrayType = Array<T>; -}; - -template <> -struct TypeTraits<WTFMap> { - using StringType = WTF::String; - template <typename T> - using ArrayType = WTFArray<T>; -}; - -// Common tests for both mojo::Map and mojo::WTFMap. -template <template <typename...> class MapType> -class MapCommonTest { - public: - using StringType = typename TypeTraits<MapType>::StringType; - template <typename T> - using ArrayType = typename TypeTraits<MapType>::template ArrayType<T>; - - // Tests null and empty maps. - static void NullAndEmpty() { - MapType<char, char> map0; - EXPECT_TRUE(map0.empty()); - EXPECT_FALSE(map0.is_null()); - map0 = nullptr; - EXPECT_TRUE(map0.is_null()); - EXPECT_FALSE(map0.empty()); - - MapType<char, char> map1(nullptr); - EXPECT_TRUE(map1.is_null()); - EXPECT_FALSE(map1.empty()); - map1.SetToEmpty(); - EXPECT_TRUE(map1.empty()); - EXPECT_FALSE(map1.is_null()); - } - - // Tests that basic Map operations work. - static void InsertWorks() { - MapType<StringType, int> map; - for (size_t i = 0; i < kStringIntDataSize; ++i) - map.insert(kStringIntData[i].string_data, kStringIntData[i].int_data); - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - EXPECT_EQ(kStringIntData[i].int_data, - map.at(kStringIntData[i].string_data)); - } - } - - static void TestIndexOperator() { - MapType<StringType, int> map; - for (size_t i = 0; i < kStringIntDataSize; ++i) - map[kStringIntData[i].string_data] = kStringIntData[i].int_data; - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - EXPECT_EQ(kStringIntData[i].int_data, - map.at(kStringIntData[i].string_data)); - } - } - - static void TestIndexOperatorAsRValue() { - MapType<StringType, int> map; - for (size_t i = 0; i < kStringIntDataSize; ++i) - map.insert(kStringIntData[i].string_data, kStringIntData[i].int_data); - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - EXPECT_EQ(kStringIntData[i].int_data, map[kStringIntData[i].string_data]); - } - } - - static void TestIndexOperatorMoveOnly() { - ASSERT_EQ(0u, MoveOnlyType::num_instances()); - MapType<StringType, ArrayType<int32_t>> map; - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - const char* key = kStringIntData[i].string_data; - ArrayType<int32_t> array(1); - array[0] = kStringIntData[i].int_data; - map[key] = std::move(array); - EXPECT_TRUE(map); - } - - // We now read back that data, to test the behavior of operator[]. - for (size_t i = 0; i < kStringIntDataSize; ++i) { - auto& value = map[kStringIntData[i].string_data]; - ASSERT_EQ(1u, value.size()); - EXPECT_EQ(kStringIntData[i].int_data, value[0]); - } - } - - static void MapArrayClone() { - MapType<StringType, ArrayType<StringType>> m; - for (size_t i = 0; i < kStringIntDataSize; ++i) { - ArrayType<StringType> s(1); - s[0] = StringType(kStringIntData[i].string_data); - m.insert(kStringIntData[i].string_data, std::move(s)); - } - - MapType<StringType, ArrayType<StringType>> m2 = m.Clone(); - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - ASSERT_NE(m2.end(), m2.find(kStringIntData[i].string_data)); - ASSERT_EQ(1u, m2[kStringIntData[i].string_data].size()); - EXPECT_EQ(StringType(kStringIntData[i].string_data), - m2[kStringIntData[i].string_data][0]); - } - } - - static void ArrayOfMap() { - { - using MojomType = Array<Map<int32_t, int8_t>>; - using UserType = ArrayType<MapType<int32_t, int8_t>>; - - UserType array(1); - array[0].insert(1, 42); - - mojo::internal::SerializationContext context; - size_t size = - mojo::internal::PrepareToSerialize<MojomType>(array, &context); - mojo::internal::FixedBufferForTesting buf(size); - typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; - mojo::internal::ContainerValidateParams validate_params( - 0, false, - new mojo::internal::ContainerValidateParams( - new mojo::internal::ContainerValidateParams(0, false, nullptr), - new mojo::internal::ContainerValidateParams(0, false, nullptr))); - - mojo::internal::Serialize<MojomType>(array, &buf, &data, &validate_params, - &context); - - UserType deserialized_array; - mojo::internal::Deserialize<MojomType>(data, &deserialized_array, - &context); - - ASSERT_EQ(1u, deserialized_array.size()); - ASSERT_EQ(1u, deserialized_array[0].size()); - ASSERT_EQ(42, deserialized_array[0].at(1)); - } - - { - using MojomType = Array<Map<String, Array<bool>>>; - using UserType = ArrayType<MapType<StringType, ArrayType<bool>>>; - - UserType array(1); - ArrayType<bool> map_value(2); - map_value[0] = false; - map_value[1] = true; - array[0].insert("hello world", std::move(map_value)); - - mojo::internal::SerializationContext context; - size_t size = - mojo::internal::PrepareToSerialize<MojomType>(array, &context); - mojo::internal::FixedBufferForTesting buf(size); - typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; - mojo::internal::ContainerValidateParams validate_params( - 0, false, - new mojo::internal::ContainerValidateParams( - new mojo::internal::ContainerValidateParams( - 0, false, new mojo::internal::ContainerValidateParams( - 0, false, nullptr)), - new mojo::internal::ContainerValidateParams( - 0, false, new mojo::internal::ContainerValidateParams( - 0, false, nullptr)))); - mojo::internal::Serialize<MojomType>(array, &buf, &data, &validate_params, - &context); - - UserType deserialized_array; - mojo::internal::Deserialize<MojomType>(data, &deserialized_array, - &context); - - ASSERT_EQ(1u, deserialized_array.size()); - ASSERT_EQ(1u, deserialized_array[0].size()); - ASSERT_FALSE(deserialized_array[0].at("hello world")[0]); - ASSERT_TRUE(deserialized_array[0].at("hello world")[1]); - } - } -}; - -#define MAP_COMMON_TEST(MapType, test_name) \ - TEST_F(MapType##Test, test_name) { MapCommonTest<MapType>::test_name(); } - -} // namespace test -} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/map_unittest.cc b/mojo/public/cpp/bindings/tests/map_unittest.cc index c74a15d..8d630a5 100644 --- a/mojo/public/cpp/bindings/tests/map_unittest.cc +++ b/mojo/public/cpp/bindings/tests/map_unittest.cc @@ -1,225 +1,44 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. +// Copyright 2017 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 "mojo/public/cpp/bindings/map.h" - #include <stddef.h> #include <stdint.h> +#include <unordered_map> #include <utility> -#include "mojo/public/cpp/bindings/array.h" -#include "mojo/public/cpp/bindings/string.h" -#include "mojo/public/cpp/bindings/tests/container_test_util.h" -#include "mojo/public/cpp/bindings/tests/map_common_test.h" +#include "mojo/public/cpp/bindings/tests/rect_chromium.h" +#include "mojo/public/interfaces/bindings/tests/rect.mojom.h" +#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { namespace test { - namespace { -using MapTest = testing::Test; - -MAP_COMMON_TEST(Map, NullAndEmpty) -MAP_COMMON_TEST(Map, InsertWorks) -MAP_COMMON_TEST(Map, TestIndexOperator) -MAP_COMMON_TEST(Map, TestIndexOperatorAsRValue) -MAP_COMMON_TEST(Map, TestIndexOperatorMoveOnly) -MAP_COMMON_TEST(Map, MapArrayClone) -MAP_COMMON_TEST(Map, ArrayOfMap) - -TEST_F(MapTest, ConstructedFromArray) { - Array<String> keys(kStringIntDataSize); - Array<int> values(kStringIntDataSize); - for (size_t i = 0; i < kStringIntDataSize; ++i) { - keys[i] = kStringIntData[i].string_data; - values[i] = kStringIntData[i].int_data; - } - - Map<String, int> map(std::move(keys), std::move(values)); - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - EXPECT_EQ(kStringIntData[i].int_data, - map.at(mojo::String(kStringIntData[i].string_data))); - } -} - -TEST_F(MapTest, DecomposeMapTo) { - Array<String> keys(kStringIntDataSize); - Array<int> values(kStringIntDataSize); - for (size_t i = 0; i < kStringIntDataSize; ++i) { - keys[i] = kStringIntData[i].string_data; - values[i] = kStringIntData[i].int_data; - } - - Map<String, int> map(std::move(keys), std::move(values)); - EXPECT_EQ(kStringIntDataSize, map.size()); - - Array<String> keys2; - Array<int> values2; - map.DecomposeMapTo(&keys2, &values2); - EXPECT_EQ(0u, map.size()); +TEST(MapTest, StructKey) { + std::unordered_map<RectPtr, int32_t> map; + map.insert(std::make_pair(Rect::New(1, 2, 3, 4), 123)); - EXPECT_EQ(kStringIntDataSize, keys2.size()); - EXPECT_EQ(kStringIntDataSize, values2.size()); + RectPtr key = Rect::New(1, 2, 3, 4); + ASSERT_NE(map.end(), map.find(key)); + ASSERT_EQ(123, map.find(key)->second); - for (size_t i = 0; i < kStringIntDataSize; ++i) { - // We are not guaranteed that the copies have the same sorting as the - // originals. - String key = kStringIntData[i].string_data; - int value = kStringIntData[i].int_data; - - bool found = false; - for (size_t j = 0; j < keys2.size(); ++j) { - if (keys2[j] == key) { - EXPECT_EQ(value, values2[j]); - found = true; - break; - } - } - - EXPECT_TRUE(found); - } -} - -TEST_F(MapTest, Insert_Copyable) { - ASSERT_EQ(0u, CopyableType::num_instances()); - mojo::Map<mojo::String, CopyableType> map; - std::vector<CopyableType*> value_ptrs; - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - const char* key = kStringIntData[i].string_data; - CopyableType value; - value_ptrs.push_back(value.ptr()); - map.insert(key, value); - ASSERT_EQ(i + 1, map.size()); - ASSERT_EQ(i + 1, value_ptrs.size()); - EXPECT_EQ(map.size() + 1, CopyableType::num_instances()); - EXPECT_TRUE(map.at(key).copied()); - EXPECT_EQ(value_ptrs[i], map.at(key).ptr()); - map.at(key).ResetCopied(); - EXPECT_TRUE(map); - } - - // std::map doesn't have a capacity() method like std::vector so this test is - // a lot more boring. - - map = nullptr; - EXPECT_EQ(0u, CopyableType::num_instances()); + map.erase(key); + ASSERT_EQ(0u, map.size()); } -TEST_F(MapTest, Insert_MoveOnly) { - ASSERT_EQ(0u, MoveOnlyType::num_instances()); - mojo::Map<mojo::String, MoveOnlyType> map; - std::vector<MoveOnlyType*> value_ptrs; - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - const char* key = kStringIntData[i].string_data; - MoveOnlyType value; - value_ptrs.push_back(value.ptr()); - map.insert(key, std::move(value)); - ASSERT_EQ(i + 1, map.size()); - ASSERT_EQ(i + 1, value_ptrs.size()); - EXPECT_EQ(map.size() + 1, MoveOnlyType::num_instances()); - EXPECT_TRUE(map.at(key).moved()); - EXPECT_EQ(value_ptrs[i], map.at(key).ptr()); - map.at(key).ResetMoved(); - EXPECT_TRUE(map); - } - - // std::map doesn't have a capacity() method like std::vector so this test is - // a lot more boring. - - map = nullptr; - EXPECT_EQ(0u, MoveOnlyType::num_instances()); -} - -TEST_F(MapTest, IndexOperator_MoveOnly) { - ASSERT_EQ(0u, MoveOnlyType::num_instances()); - mojo::Map<mojo::String, MoveOnlyType> map; - std::vector<MoveOnlyType*> value_ptrs; - - for (size_t i = 0; i < kStringIntDataSize; ++i) { - const char* key = kStringIntData[i].string_data; - MoveOnlyType value; - value_ptrs.push_back(value.ptr()); - map[key] = std::move(value); - ASSERT_EQ(i + 1, map.size()); - ASSERT_EQ(i + 1, value_ptrs.size()); - EXPECT_EQ(map.size() + 1, MoveOnlyType::num_instances()); - EXPECT_TRUE(map.at(key).moved()); - EXPECT_EQ(value_ptrs[i], map.at(key).ptr()); - map.at(key).ResetMoved(); - EXPECT_TRUE(map); - } - - // std::map doesn't have a capacity() method like std::vector so this test is - // a lot more boring. - - map = nullptr; - EXPECT_EQ(0u, MoveOnlyType::num_instances()); -} - -TEST_F(MapTest, STLToMojo) { - std::map<std::string, int> stl_data; - for (size_t i = 0; i < kStringIntDataSize; ++i) - stl_data[kStringIntData[i].string_data] = kStringIntData[i].int_data; - - Map<String, int32_t> mojo_data = Map<String, int32_t>::From(stl_data); - for (size_t i = 0; i < kStringIntDataSize; ++i) { - EXPECT_EQ(kStringIntData[i].int_data, - mojo_data.at(kStringIntData[i].string_data)); - } -} - -TEST_F(MapTest, MojoToSTL) { - Map<String, int32_t> mojo_map; - for (size_t i = 0; i < kStringIntDataSize; ++i) - mojo_map.insert(kStringIntData[i].string_data, kStringIntData[i].int_data); - - std::map<std::string, int> stl_map = - mojo_map.To<std::map<std::string, int>>(); - for (size_t i = 0; i < kStringIntDataSize; ++i) { - auto it = stl_map.find(kStringIntData[i].string_data); - ASSERT_TRUE(it != stl_map.end()); - EXPECT_EQ(kStringIntData[i].int_data, it->second); - } -} - -TEST_F(MapTest, MoveFromAndToSTLMap_Copyable) { - std::map<int32_t, CopyableType> map1; - map1.insert(std::make_pair(123, CopyableType())); - map1[123].ResetCopied(); - - Map<int32_t, CopyableType> mojo_map(std::move(map1)); - ASSERT_EQ(1u, mojo_map.size()); - ASSERT_NE(mojo_map.end(), mojo_map.find(123)); - ASSERT_FALSE(mojo_map[123].copied()); - - std::map<int32_t, CopyableType> map2(mojo_map.PassStorage()); - ASSERT_EQ(1u, map2.size()); - ASSERT_NE(map2.end(), map2.find(123)); - ASSERT_FALSE(map2[123].copied()); - - ASSERT_EQ(0u, mojo_map.size()); - ASSERT_TRUE(mojo_map.is_null()); -} - -TEST_F(MapTest, MoveFromAndToSTLMap_MoveOnly) { - std::map<int32_t, MoveOnlyType> map1; - map1.insert(std::make_pair(123, MoveOnlyType())); - - Map<int32_t, MoveOnlyType> mojo_map(std::move(map1)); - ASSERT_EQ(1u, mojo_map.size()); - ASSERT_NE(mojo_map.end(), mojo_map.find(123)); +TEST(MapTest, TypemappedStructKey) { + std::unordered_map<ContainsHashablePtr, int32_t> map; + map.insert( + std::make_pair(ContainsHashable::New(RectChromium(1, 2, 3, 4)), 123)); - std::map<int32_t, MoveOnlyType> map2(mojo_map.PassStorage()); - ASSERT_EQ(1u, map2.size()); - ASSERT_NE(map2.end(), map2.find(123)); + ContainsHashablePtr key = ContainsHashable::New(RectChromium(1, 2, 3, 4)); + ASSERT_NE(map.end(), map.find(key)); + ASSERT_EQ(123, map.find(key)->second); - ASSERT_EQ(0u, mojo_map.size()); - ASSERT_TRUE(mojo_map.is_null()); + map.erase(key); + ASSERT_EQ(0u, map.size()); } } // namespace diff --git a/mojo/public/cpp/bindings/tests/message_queue.cc b/mojo/public/cpp/bindings/tests/message_queue.cc index 96a4829..32ed763 100644 --- a/mojo/public/cpp/bindings/tests/message_queue.cc +++ b/mojo/public/cpp/bindings/tests/message_queue.cc @@ -14,8 +14,6 @@ MessageQueue::MessageQueue() { } MessageQueue::~MessageQueue() { - while (!queue_.empty()) - Pop(); } bool MessageQueue::IsEmpty() const { @@ -23,19 +21,17 @@ bool MessageQueue::IsEmpty() const { } void MessageQueue::Push(Message* message) { - queue_.push(new Message()); - message->MoveTo(queue_.back()); + queue_.emplace(std::move(*message)); } void MessageQueue::Pop(Message* message) { DCHECK(!queue_.empty()); - queue_.front()->MoveTo(message); + *message = std::move(queue_.front()); Pop(); } void MessageQueue::Pop() { DCHECK(!queue_.empty()); - delete queue_.front(); queue_.pop(); } diff --git a/mojo/public/cpp/bindings/tests/message_queue.h b/mojo/public/cpp/bindings/tests/message_queue.h index 8859869..8f13f7a 100644 --- a/mojo/public/cpp/bindings/tests/message_queue.h +++ b/mojo/public/cpp/bindings/tests/message_queue.h @@ -8,10 +8,9 @@ #include <queue> #include "base/macros.h" +#include "mojo/public/cpp/bindings/message.h" namespace mojo { -class Message; - namespace test { // A queue for Message objects. @@ -34,7 +33,7 @@ class MessageQueue { private: void Pop(); - std::queue<Message*> queue_; + std::queue<Message> queue_; DISALLOW_COPY_AND_ASSIGN(MessageQueue); }; diff --git a/mojo/public/cpp/bindings/tests/mojo_test_blink_export.h b/mojo/public/cpp/bindings/tests/mojo_test_blink_export.h new file mode 100644 index 0000000..b3bbe27 --- /dev/null +++ b/mojo/public/cpp/bindings/tests/mojo_test_blink_export.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_TESTS_MOJO_TEST_BLINK_EXPORT_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_TESTS_MOJO_TEST_BLINK_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(MOJO_TEST_BLINK_IMPLEMENTATION) +#define MOJO_TEST_BLINK_EXPORT __declspec(dllexport) +#else +#define MOJO_TEST_BLINK_EXPORT __declspec(dllimport) +#endif // defined(MOJO_TEST_BLINK_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(MOJO_TEST_BLINK_IMPLEMENTATION) +#define MOJO_TEST_BLINK_EXPORT __attribute__((visibility("default"))) +#else +#define MOJO_TEST_BLINK_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define MOJO_TEST_BLINK_EXPORT +#endif + +#endif // MOJO_PUBLIC_CPP_BINDINGS_TESTS_MOJO_TEST_BLINK_EXPORT_H_ diff --git a/mojo/public/cpp/bindings/tests/mojo_test_export.h b/mojo/public/cpp/bindings/tests/mojo_test_export.h new file mode 100644 index 0000000..a48a1ba --- /dev/null +++ b/mojo/public/cpp/bindings/tests/mojo_test_export.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_TESTS_MOJO_TEST_EXPORT_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_TESTS_MOJO_TEST_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(MOJO_TEST_IMPLEMENTATION) +#define MOJO_TEST_EXPORT __declspec(dllexport) +#else +#define MOJO_TEST_EXPORT __declspec(dllimport) +#endif // defined(MOJO_TEST_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(MOJO_TEST_IMPLEMENTATION) +#define MOJO_TEST_EXPORT __attribute__((visibility("default"))) +#else +#define MOJO_TEST_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define MOJO_TEST_EXPORT +#endif + +#endif // MOJO_PUBLIC_CPP_BINDINGS_TESTS_MOJO_TEST_EXPORT_H_ diff --git a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc index 9bfcf2c..31963e0 100644 --- a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc +++ b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc @@ -14,7 +14,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "mojo/public/cpp/bindings/interface_endpoint_client.h" #include "mojo/public/cpp/bindings/message.h" -#include "mojo/public/cpp/bindings/message_filter.h" #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" #include "mojo/public/cpp/bindings/tests/message_queue.h" #include "mojo/public/cpp/bindings/tests/router_test_util.h" @@ -32,27 +31,22 @@ class MultiplexRouterTest : public testing::Test { void SetUp() override { MessagePipe pipe; - router0_ = new MultiplexRouter(true, std::move(pipe.handle0), + router0_ = new MultiplexRouter(std::move(pipe.handle0), + MultiplexRouter::MULTI_INTERFACE, false, base::ThreadTaskRunnerHandle::Get()); - router1_ = new MultiplexRouter(true, std::move(pipe.handle1), + router1_ = new MultiplexRouter(std::move(pipe.handle1), + MultiplexRouter::MULTI_INTERFACE, true, base::ThreadTaskRunnerHandle::Get()); - router0_->CreateEndpointHandlePair(&endpoint0_, &endpoint1_); - endpoint1_ = - EmulatePassingEndpointHandle(std::move(endpoint1_), router1_.get()); + ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0_, + &endpoint1_); + auto id = router0_->AssociateInterface(std::move(endpoint1_)); + endpoint1_ = router1_->CreateLocalEndpointHandle(id); } void TearDown() override {} void PumpMessages() { base::RunLoop().RunUntilIdle(); } - ScopedInterfaceEndpointHandle EmulatePassingEndpointHandle( - ScopedInterfaceEndpointHandle handle, - MultiplexRouter* target) { - CHECK(!handle.is_local()); - - return target->CreateLocalEndpointHandle(handle.release()); - } - protected: scoped_refptr<MultiplexRouter> router0_; scoped_refptr<MultiplexRouter> router1_; @@ -65,12 +59,12 @@ class MultiplexRouterTest : public testing::Test { TEST_F(MultiplexRouterTest, BasicRequestResponse) { InterfaceEndpointClient client0(std::move(endpoint0_), nullptr, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + base::MakeUnique<PassThroughFilter>(), false, + base::ThreadTaskRunnerHandle::Get(), 0u); ResponseGenerator generator; InterfaceEndpointClient client1(std::move(endpoint1_), &generator, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + base::MakeUnique<PassThroughFilter>(), false, + base::ThreadTaskRunnerHandle::Get(), 0u); Message request; AllocRequestMessage(1, "hello", &request); @@ -112,12 +106,12 @@ TEST_F(MultiplexRouterTest, BasicRequestResponse) { TEST_F(MultiplexRouterTest, BasicRequestResponse_Synchronous) { InterfaceEndpointClient client0(std::move(endpoint0_), nullptr, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + base::MakeUnique<PassThroughFilter>(), false, + base::ThreadTaskRunnerHandle::Get(), 0u); ResponseGenerator generator; InterfaceEndpointClient client1(std::move(endpoint1_), &generator, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + base::MakeUnique<PassThroughFilter>(), false, + base::ThreadTaskRunnerHandle::Get(), 0u); Message request; AllocRequestMessage(1, "hello", &request); @@ -154,46 +148,18 @@ TEST_F(MultiplexRouterTest, BasicRequestResponse_Synchronous) { std::string(reinterpret_cast<const char*>(response.payload()))); } -TEST_F(MultiplexRouterTest, RequestWithNoReceiver) { - InterfaceEndpointClient client0(std::move(endpoint0_), nullptr, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); - InterfaceEndpointClient client1(std::move(endpoint1_), nullptr, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); - - // Without an incoming receiver set on client1, we expect client0 to observe - // an error as a result of sending a message. - - Message request; - AllocRequestMessage(1, "hello", &request); - - MessageQueue message_queue; - base::RunLoop run_loop, run_loop2; - client0.set_connection_error_handler(run_loop.QuitClosure()); - client1.set_connection_error_handler(run_loop2.QuitClosure()); - client0.AcceptWithResponder( - &request, new MessageAccumulator(&message_queue, run_loop.QuitClosure())); - - run_loop.Run(); - run_loop2.Run(); - - EXPECT_TRUE(client0.encountered_error()); - EXPECT_TRUE(client1.encountered_error()); - EXPECT_TRUE(message_queue.IsEmpty()); -} - // Tests MultiplexRouter using the LazyResponseGenerator. The responses will not // be sent until after the requests have been accepted. TEST_F(MultiplexRouterTest, LazyResponses) { - InterfaceEndpointClient client0(std::move(endpoint0_), nullptr, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + InterfaceEndpointClient client0( + std::move(endpoint0_), nullptr, base::WrapUnique(new PassThroughFilter()), + false, base::ThreadTaskRunnerHandle::Get(), 0u); base::RunLoop run_loop; LazyResponseGenerator generator(run_loop.QuitClosure()); InterfaceEndpointClient client1(std::move(endpoint1_), &generator, base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + false, base::ThreadTaskRunnerHandle::Get(), + 0u); Message request; AllocRequestMessage(1, "hello", &request); @@ -257,9 +223,9 @@ void ForwardErrorHandler(bool* called, const base::Closure& callback) { // both sides still appear to have a valid message pipe handle bound. TEST_F(MultiplexRouterTest, MissingResponses) { base::RunLoop run_loop0, run_loop1; - InterfaceEndpointClient client0(std::move(endpoint0_), nullptr, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + InterfaceEndpointClient client0( + std::move(endpoint0_), nullptr, base::WrapUnique(new PassThroughFilter()), + false, base::ThreadTaskRunnerHandle::Get(), 0u); bool error_handler_called0 = false; client0.set_connection_error_handler( base::Bind(&ForwardErrorHandler, &error_handler_called0, @@ -269,7 +235,8 @@ TEST_F(MultiplexRouterTest, MissingResponses) { LazyResponseGenerator generator(run_loop3.QuitClosure()); InterfaceEndpointClient client1(std::move(endpoint1_), &generator, base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + false, base::ThreadTaskRunnerHandle::Get(), + 0u); bool error_handler_called1 = false; client1.set_connection_error_handler( base::Bind(&ForwardErrorHandler, &error_handler_called1, @@ -314,12 +281,13 @@ TEST_F(MultiplexRouterTest, LateResponse) { base::RunLoop run_loop; LazyResponseGenerator generator(run_loop.QuitClosure()); { - InterfaceEndpointClient client0(std::move(endpoint0_), nullptr, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + InterfaceEndpointClient client0( + std::move(endpoint0_), nullptr, base::MakeUnique<PassThroughFilter>(), + false, base::ThreadTaskRunnerHandle::Get(), 0u); InterfaceEndpointClient client1(std::move(endpoint1_), &generator, - base::WrapUnique(new PassThroughFilter()), - false, base::ThreadTaskRunnerHandle::Get()); + base::MakeUnique<PassThroughFilter>(), + false, base::ThreadTaskRunnerHandle::Get(), + 0u); Message request; AllocRequestMessage(1, "hello", &request); diff --git a/mojo/public/cpp/bindings/tests/pickle_unittest.cc b/mojo/public/cpp/bindings/tests/pickle_unittest.cc index bd716cc..a5947ce 100644 --- a/mojo/public/cpp/bindings/tests/pickle_unittest.cc +++ b/mojo/public/cpp/bindings/tests/pickle_unittest.cc @@ -24,28 +24,25 @@ namespace test { namespace { template <typename T> -void DoExpectResult(int foo, - int bar, - const base::Closure& callback, - const T& actual) { +void DoExpectResult(int foo, int bar, const base::Closure& callback, T actual) { EXPECT_EQ(foo, actual.foo()); EXPECT_EQ(bar, actual.bar()); callback.Run(); } template <typename T> -base::Callback<void(const T&)> ExpectResult(const T& t, - const base::Closure& callback) { +base::Callback<void(T)> ExpectResult(const T& t, + const base::Closure& callback) { return base::Bind(&DoExpectResult<T>, t.foo(), t.bar(), callback); } template <typename T> -void DoFail(const std::string& reason, const T&) { +void DoFail(const std::string& reason, T) { EXPECT_TRUE(false) << reason; } template <typename T> -base::Callback<void(const T&)> Fail(const std::string& reason) { +base::Callback<void(T)> Fail(const std::string& reason) { return base::Bind(&DoFail<T>, reason); } @@ -89,9 +86,9 @@ class ChromiumPicklePasserImpl : public PicklePasser { ChromiumPicklePasserImpl() {} // mojo::test::PicklePasser: - void PassPickledStruct(const PickledStructChromium& pickle, + void PassPickledStruct(PickledStructChromium pickle, const PassPickledStructCallback& callback) override { - callback.Run(pickle); + callback.Run(std::move(pickle)); } void PassPickledEnum(PickledEnumChromium pickle, @@ -105,15 +102,15 @@ class ChromiumPicklePasserImpl : public PicklePasser { callback.Run(std::move(container)); } - void PassPickles(const std::vector<PickledStructChromium>& pickles, + void PassPickles(std::vector<PickledStructChromium> pickles, const PassPicklesCallback& callback) override { - callback.Run(pickles); + callback.Run(std::move(pickles)); } void PassPickleArrays( - const std::vector<std::vector<PickledStructChromium>>& pickle_arrays, + std::vector<std::vector<PickledStructChromium>> pickle_arrays, const PassPickleArraysCallback& callback) override { - callback.Run(pickle_arrays); + callback.Run(std::move(pickle_arrays)); } }; @@ -123,9 +120,9 @@ class BlinkPicklePasserImpl : public blink::PicklePasser { BlinkPicklePasserImpl() {} // mojo::test::blink::PicklePasser: - void PassPickledStruct(const PickledStructBlink& pickle, + void PassPickledStruct(PickledStructBlink pickle, const PassPickledStructCallback& callback) override { - callback.Run(pickle); + callback.Run(std::move(pickle)); } void PassPickledEnum(PickledEnumBlink pickle, @@ -139,15 +136,15 @@ class BlinkPicklePasserImpl : public blink::PicklePasser { callback.Run(std::move(container)); } - void PassPickles(const WTF::Vector<PickledStructBlink>& pickles, + void PassPickles(WTF::Vector<PickledStructBlink> pickles, const PassPicklesCallback& callback) override { - callback.Run(pickles); + callback.Run(std::move(pickles)); } void PassPickleArrays( - const WTF::Vector<WTF::Vector<PickledStructBlink>>& pickle_arrays, + WTF::Vector<WTF::Vector<PickledStructBlink>> pickle_arrays, const PassPickleArraysCallback& callback) override { - callback.Run(pickle_arrays); + callback.Run(std::move(pickle_arrays)); } }; @@ -160,7 +157,7 @@ class PickleTest : public testing::Test { template <typename ProxyType = PicklePasser> InterfacePtr<ProxyType> ConnectToChromiumService() { InterfacePtr<ProxyType> proxy; - InterfaceRequest<ProxyType> request = GetProxy(&proxy); + InterfaceRequest<ProxyType> request(&proxy); chromium_bindings_.AddBinding( &chromium_service_, ConvertInterfaceRequest<PicklePasser>(std::move(request))); @@ -170,7 +167,7 @@ class PickleTest : public testing::Test { template <typename ProxyType = blink::PicklePasser> InterfacePtr<ProxyType> ConnectToBlinkService() { InterfacePtr<ProxyType> proxy; - InterfaceRequest<ProxyType> request = GetProxy(&proxy); + InterfaceRequest<ProxyType> request(&proxy); blink_bindings_.AddBinding( &blink_service_, ConvertInterfaceRequest<blink::PicklePasser>(std::move(request))); @@ -301,7 +298,7 @@ TEST_F(PickleTest, BlinkProxyToChromiumService) { TEST_F(PickleTest, PickleArray) { auto proxy = ConnectToChromiumService(); - auto pickles = Array<PickledStructChromium>::New(2); + auto pickles = std::vector<PickledStructChromium>(2); pickles[0].set_foo(1); pickles[0].set_bar(2); pickles[0].set_baz(100); @@ -314,19 +311,18 @@ TEST_F(PickleTest, PickleArray) { // deserialized intact. This ensures that the ParamTraits are actually used // rather than doing a byte-for-byte copy of the element data, beacuse the // |baz| field should never be serialized. - proxy->PassPickles( - std::move(pickles), - BindSimpleLambda<const std::vector<PickledStructChromium>&>( - [&](const std::vector<PickledStructChromium>& passed) { - ASSERT_EQ(2u, passed.size()); - EXPECT_EQ(1, passed[0].foo()); - EXPECT_EQ(2, passed[0].bar()); - EXPECT_EQ(0, passed[0].baz()); - EXPECT_EQ(3, passed[1].foo()); - EXPECT_EQ(4, passed[1].bar()); - EXPECT_EQ(0, passed[1].baz()); - run_loop.Quit(); - })); + proxy->PassPickles(std::move(pickles), + BindSimpleLambda<std::vector<PickledStructChromium>>( + [&](std::vector<PickledStructChromium> passed) { + ASSERT_EQ(2u, passed.size()); + EXPECT_EQ(1, passed[0].foo()); + EXPECT_EQ(2, passed[0].bar()); + EXPECT_EQ(0, passed[0].baz()); + EXPECT_EQ(3, passed[1].foo()); + EXPECT_EQ(4, passed[1].bar()); + EXPECT_EQ(0, passed[1].baz()); + run_loop.Quit(); + })); run_loop.Run(); } } @@ -353,10 +349,9 @@ TEST_F(PickleTest, PickleArrayArray) { base::RunLoop run_loop; // Verify that the array-of-arrays serializes and deserializes properly. proxy->PassPickleArrays( - pickle_arrays, - BindSimpleLambda< - const std::vector<std::vector<PickledStructChromium>>&>( - [&](const std::vector<std::vector<PickledStructChromium>>& passed) { + std::move(pickle_arrays), + BindSimpleLambda<std::vector<std::vector<PickledStructChromium>>>( + [&](std::vector<std::vector<PickledStructChromium>> passed) { ASSERT_EQ(2u, passed.size()); ASSERT_EQ(2u, passed[0].size()); ASSERT_EQ(2u, passed[1].size()); diff --git a/mojo/public/cpp/bindings/tests/pickled_types_blink.h b/mojo/public/cpp/bindings/tests/pickled_types_blink.h index 0b7bd20..37e9e70 100644 --- a/mojo/public/cpp/bindings/tests/pickled_types_blink.h +++ b/mojo/public/cpp/bindings/tests/pickled_types_blink.h @@ -51,9 +51,14 @@ class PickledStructBlink { bar_ = bar; } + // The |baz| field should never be serialized. + int baz() const { return baz_; } + void set_baz(int baz) { baz_ = baz; } + private: int foo_ = 0; int bar_ = 0; + int baz_ = 0; DISALLOW_COPY_AND_ASSIGN(PickledStructBlink); }; diff --git a/mojo/public/cpp/bindings/tests/rect_blink.h b/mojo/public/cpp/bindings/tests/rect_blink.h index de7a792..7335989 100644 --- a/mojo/public/cpp/bindings/tests/rect_blink.h +++ b/mojo/public/cpp/bindings/tests/rect_blink.h @@ -51,6 +51,12 @@ class RectBlink { int computeArea() const { return width_ * height_; } + bool operator==(const RectBlink& other) const { + return (x() == other.x() && y() == other.y() && width() == other.width() && + height() == other.height()); + } + bool operator!=(const RectBlink& other) const { return !(*this == other); } + private: int x_ = 0; int y_ = 0; @@ -61,4 +67,17 @@ class RectBlink { } // namespace test } // namespace mojo +namespace std { + +template <> +struct hash<mojo::test::RectBlink> { + size_t operator()(const mojo::test::RectBlink& value) { + // Terrible hash function: + return (std::hash<int>()(value.x()) ^ std::hash<int>()(value.y()) ^ + std::hash<int>()(value.width()) ^ std::hash<int>()(value.height())); + } +}; + +} // namespace std + #endif // MOJO_PUBLIC_CPP_BINDINGS_TESTS_RECT_BLINK_H_ diff --git a/mojo/public/cpp/bindings/tests/rect_blink.typemap b/mojo/public/cpp/bindings/tests/rect_blink.typemap index 37ee409..657ea1a 100644 --- a/mojo/public/cpp/bindings/tests/rect_blink.typemap +++ b/mojo/public/cpp/bindings/tests/rect_blink.typemap @@ -3,7 +3,16 @@ # found in the LICENSE file. mojom = "//mojo/public/interfaces/bindings/tests/rect.mojom" -public_headers = [ "//mojo/public/cpp/bindings/tests/rect_blink.h" ] -traits_headers = [ "//mojo/public/cpp/bindings/tests/rect_blink_traits.h" ] +public_headers = [ + "//mojo/public/cpp/bindings/tests/rect_blink.h", + "//mojo/public/cpp/bindings/tests/shared_rect.h", +] +traits_headers = [ + "//mojo/public/cpp/bindings/tests/rect_blink_traits.h", + "//mojo/public/cpp/bindings/tests/shared_rect_traits.h", +] -type_mappings = [ "mojo.test.TypemappedRect=mojo::test::RectBlink" ] +type_mappings = [ + "mojo.test.TypemappedRect=mojo::test::RectBlink[hashable]", + "mojo.test.SharedTypemappedRect=mojo::test::SharedRect", +] diff --git a/mojo/public/cpp/bindings/tests/rect_blink_traits.h b/mojo/public/cpp/bindings/tests/rect_blink_traits.h index c5f6068..7258739 100644 --- a/mojo/public/cpp/bindings/tests/rect_blink_traits.h +++ b/mojo/public/cpp/bindings/tests/rect_blink_traits.h @@ -12,14 +12,13 @@ namespace mojo { template <> -struct StructTraits<test::blink::TypemappedRect, test::RectBlink> { +struct StructTraits<test::TypemappedRectDataView, test::RectBlink> { static int x(const test::RectBlink& r) { return r.x(); } static int y(const test::RectBlink& r) { return r.y(); } static int width(const test::RectBlink& r) { return r.width(); } static int height(const test::RectBlink& r) { return r.height(); } - static bool Read(test::blink::TypemappedRectDataView r, - test::RectBlink* out) { + static bool Read(test::TypemappedRectDataView r, test::RectBlink* out) { if (r.x() < 0 || r.y() < 0 || r.width() < 0 || r.height() < 0) { return false; } diff --git a/mojo/public/cpp/bindings/tests/rect_chromium.h b/mojo/public/cpp/bindings/tests/rect_chromium.h index 20c4362..d2e0a3e 100644 --- a/mojo/public/cpp/bindings/tests/rect_chromium.h +++ b/mojo/public/cpp/bindings/tests/rect_chromium.h @@ -55,6 +55,12 @@ class RectChromium { int GetArea() const { return width_ * height_; } + bool operator==(const RectChromium& other) const { + return (x() == other.x() && y() == other.y() && width() == other.width() && + height() == other.height()); + } + bool operator!=(const RectChromium& other) const { return !(*this == other); } + private: int x_ = 0; int y_ = 0; @@ -65,4 +71,17 @@ class RectChromium { } // namespace test } // namespace mojo +namespace std { + +template <> +struct hash<mojo::test::RectChromium> { + size_t operator()(const mojo::test::RectChromium& value) { + // Terrible hash function: + return (std::hash<int>()(value.x()) ^ std::hash<int>()(value.y()) ^ + std::hash<int>()(value.width()) ^ std::hash<int>()(value.height())); + } +}; + +} // namespace std + #endif // MOJO_PUBLIC_CPP_BINDINGS_TESTS_RECT_CHROMIUM_H_ diff --git a/mojo/public/cpp/bindings/tests/rect_chromium.typemap b/mojo/public/cpp/bindings/tests/rect_chromium.typemap index 0da4021..7e5df84 100644 --- a/mojo/public/cpp/bindings/tests/rect_chromium.typemap +++ b/mojo/public/cpp/bindings/tests/rect_chromium.typemap @@ -3,7 +3,16 @@ # found in the LICENSE file. mojom = "//mojo/public/interfaces/bindings/tests/rect.mojom" -public_headers = [ "//mojo/public/cpp/bindings/tests/rect_chromium.h" ] -traits_headers = [ "//mojo/public/cpp/bindings/tests/rect_chromium_traits.h" ] +public_headers = [ + "//mojo/public/cpp/bindings/tests/rect_chromium.h", + "//mojo/public/cpp/bindings/tests/shared_rect.h", +] +traits_headers = [ + "//mojo/public/cpp/bindings/tests/rect_chromium_traits.h", + "//mojo/public/cpp/bindings/tests/shared_rect_traits.h", +] -type_mappings = [ "mojo.test.TypemappedRect=mojo::test::RectChromium" ] +type_mappings = [ + "mojo.test.TypemappedRect=mojo::test::RectChromium[hashable]", + "mojo.test.SharedTypemappedRect=mojo::test::SharedRect", +] diff --git a/mojo/public/cpp/bindings/tests/rect_chromium_traits.h b/mojo/public/cpp/bindings/tests/rect_chromium_traits.h index ab65371..b446d7d 100644 --- a/mojo/public/cpp/bindings/tests/rect_chromium_traits.h +++ b/mojo/public/cpp/bindings/tests/rect_chromium_traits.h @@ -12,7 +12,7 @@ namespace mojo { template <> -struct StructTraits<test::TypemappedRect, test::RectChromium> { +struct StructTraits<test::TypemappedRectDataView, test::RectChromium> { static int x(const test::RectChromium& r) { return r.x(); } static int y(const test::RectChromium& r) { return r.y(); } static int width(const test::RectChromium& r) { return r.width(); } diff --git a/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc b/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc new file mode 100644 index 0000000..1bf3f7a --- /dev/null +++ b/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc @@ -0,0 +1,194 @@ +// 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 "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/interfaces/bindings/tests/test_bad_messages.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace test { +namespace { + +class TestBadMessagesImpl : public TestBadMessages { + public: + TestBadMessagesImpl() : binding_(this) {} + ~TestBadMessagesImpl() override {} + + void BindImpl(TestBadMessagesRequest request) { + binding_.Bind(std::move(request)); + } + + const ReportBadMessageCallback& bad_message_callback() { + return bad_message_callback_; + } + + private: + // TestBadMessages: + void RejectEventually(const RejectEventuallyCallback& callback) override { + bad_message_callback_ = GetBadMessageCallback(); + callback.Run(); + } + + void RequestResponse(const RequestResponseCallback& callback) override { + callback.Run(); + } + + void RejectSync(const RejectSyncCallback& callback) override { + callback.Run(); + ReportBadMessage("go away"); + } + + void RequestResponseSync( + const RequestResponseSyncCallback& callback) override { + callback.Run(); + } + + ReportBadMessageCallback bad_message_callback_; + mojo::Binding<TestBadMessages> binding_; + + DISALLOW_COPY_AND_ASSIGN(TestBadMessagesImpl); +}; + +class ReportBadMessageTest : public testing::Test { + public: + ReportBadMessageTest() {} + + void SetUp() override { + mojo::edk::SetDefaultProcessErrorCallback( + base::Bind(&ReportBadMessageTest::OnProcessError, + base::Unretained(this))); + + impl_.BindImpl(MakeRequest(&proxy_)); + } + + void TearDown() override { + mojo::edk::SetDefaultProcessErrorCallback( + mojo::edk::ProcessErrorCallback()); + } + + TestBadMessages* proxy() { return proxy_.get(); } + + TestBadMessagesImpl* impl() { return &impl_; } + + void SetErrorHandler(const base::Closure& handler) { + error_handler_ = handler; + } + + private: + void OnProcessError(const std::string& error) { + if (!error_handler_.is_null()) + error_handler_.Run(); + } + + TestBadMessagesPtr proxy_; + TestBadMessagesImpl impl_; + base::Closure error_handler_; + base::MessageLoop message_loop; +}; + +TEST_F(ReportBadMessageTest, Request) { + // Verify that basic immediate error reporting works. + bool error = false; + SetErrorHandler(base::Bind([] (bool* flag) { *flag = true; }, &error)); + EXPECT_TRUE(proxy()->RejectSync()); + EXPECT_TRUE(error); +} + +TEST_F(ReportBadMessageTest, RequestAsync) { + bool error = false; + SetErrorHandler(base::Bind([] (bool* flag) { *flag = true; }, &error)); + + // This should capture a bad message reporting callback in the impl. + base::RunLoop loop; + proxy()->RejectEventually(loop.QuitClosure()); + loop.Run(); + + EXPECT_FALSE(error); + + // Now we can run the callback and it should trigger a bad message report. + DCHECK(!impl()->bad_message_callback().is_null()); + impl()->bad_message_callback().Run("bad!"); + EXPECT_TRUE(error); +} + +TEST_F(ReportBadMessageTest, Response) { + bool error = false; + SetErrorHandler(base::Bind([] (bool* flag) { *flag = true; }, &error)); + + base::RunLoop loop; + proxy()->RequestResponse( + base::Bind([] (const base::Closure& quit) { + // Report a bad message inside the response callback. This should + // trigger the error handler. + ReportBadMessage("no way!"); + quit.Run(); + }, + loop.QuitClosure())); + loop.Run(); + + EXPECT_TRUE(error); +} + +TEST_F(ReportBadMessageTest, ResponseAsync) { + bool error = false; + SetErrorHandler(base::Bind([] (bool* flag) { *flag = true; }, &error)); + + ReportBadMessageCallback bad_message_callback; + base::RunLoop loop; + proxy()->RequestResponse( + base::Bind([] (const base::Closure& quit, + ReportBadMessageCallback* callback) { + // Capture the bad message callback inside the response callback. + *callback = GetBadMessageCallback(); + quit.Run(); + }, + loop.QuitClosure(), &bad_message_callback)); + loop.Run(); + + EXPECT_FALSE(error); + + // Invoking this callback should report a bad message and trigger the error + // handler immediately. + bad_message_callback.Run("this message is bad and should feel bad"); + EXPECT_TRUE(error); +} + +TEST_F(ReportBadMessageTest, ResponseSync) { + bool error = false; + SetErrorHandler(base::Bind([] (bool* flag) { *flag = true; }, &error)); + + SyncMessageResponseContext context; + proxy()->RequestResponseSync(); + + EXPECT_FALSE(error); + context.ReportBadMessage("i don't like this response"); + EXPECT_TRUE(error); +} + +TEST_F(ReportBadMessageTest, ResponseSyncDeferred) { + bool error = false; + SetErrorHandler(base::Bind([] (bool* flag) { *flag = true; }, &error)); + + ReportBadMessageCallback bad_message_callback; + { + SyncMessageResponseContext context; + proxy()->RequestResponseSync(); + bad_message_callback = context.GetBadMessageCallback(); + } + + EXPECT_FALSE(error); + bad_message_callback.Run("nope nope nope"); + EXPECT_TRUE(error); +} + +} // namespace +} // namespace test +} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/request_response_unittest.cc b/mojo/public/cpp/bindings/tests/request_response_unittest.cc index 5e203a2..43b8f0d 100644 --- a/mojo/public/cpp/bindings/tests/request_response_unittest.cc +++ b/mojo/public/cpp/bindings/tests/request_response_unittest.cc @@ -95,7 +95,7 @@ class RequestResponseTest : public testing::Test { TEST_F(RequestResponseTest, EchoString) { sample::ProviderPtr provider; - ProviderImpl provider_impl(GetProxy(&provider)); + ProviderImpl provider_impl(MakeRequest(&provider)); std::string buf; base::RunLoop run_loop; @@ -109,7 +109,7 @@ TEST_F(RequestResponseTest, EchoString) { TEST_F(RequestResponseTest, EchoStrings) { sample::ProviderPtr provider; - ProviderImpl provider_impl(GetProxy(&provider)); + ProviderImpl provider_impl(MakeRequest(&provider)); std::string buf; base::RunLoop run_loop; @@ -123,7 +123,7 @@ TEST_F(RequestResponseTest, EchoStrings) { TEST_F(RequestResponseTest, EchoMessagePipeHandle) { sample::ProviderPtr provider; - ProviderImpl provider_impl(GetProxy(&provider)); + ProviderImpl provider_impl(MakeRequest(&provider)); MessagePipe pipe2; base::RunLoop run_loop; @@ -141,7 +141,7 @@ TEST_F(RequestResponseTest, EchoMessagePipeHandle) { TEST_F(RequestResponseTest, EchoEnum) { sample::ProviderPtr provider; - ProviderImpl provider_impl(GetProxy(&provider)); + ProviderImpl provider_impl(MakeRequest(&provider)); sample::Enum value; base::RunLoop run_loop; diff --git a/mojo/public/cpp/bindings/tests/router_test_util.cc b/mojo/public/cpp/bindings/tests/router_test_util.cc index 3e32ec7..b9b93d8 100644 --- a/mojo/public/cpp/bindings/tests/router_test_util.cc +++ b/mojo/public/cpp/bindings/tests/router_test_util.cc @@ -17,10 +17,10 @@ namespace test { void AllocRequestMessage(uint32_t name, const char* text, Message* message) { size_t payload_size = strlen(text) + 1; // Plus null terminator. - internal::RequestMessageBuilder builder(name, payload_size); + internal::MessageBuilder builder(name, Message::kFlagExpectsResponse, + payload_size, 0); memcpy(builder.buffer()->Allocate(payload_size), text, payload_size); - - builder.message()->MoveTo(message); + *message = std::move(*builder.message()); } void AllocResponseMessage(uint32_t name, @@ -28,10 +28,11 @@ void AllocResponseMessage(uint32_t name, uint64_t request_id, Message* message) { size_t payload_size = strlen(text) + 1; // Plus null terminator. - internal::ResponseMessageBuilder builder(name, payload_size, request_id); + internal::MessageBuilder builder(name, Message::kFlagIsResponse, payload_size, + 0); + builder.message()->set_request_id(request_id); memcpy(builder.buffer()->Allocate(payload_size), text, payload_size); - - builder.message()->MoveTo(message); + *message = std::move(*builder.message()); } MessageAccumulator::MessageAccumulator(MessageQueue* queue, diff --git a/mojo/public/cpp/bindings/tests/router_unittest.cc b/mojo/public/cpp/bindings/tests/router_unittest.cc deleted file mode 100644 index 39a8363..0000000 --- a/mojo/public/cpp/bindings/tests/router_unittest.cc +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2014 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 "mojo/public/cpp/bindings/lib/router.h" - -#include <utility> - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/threading/thread_task_runner_handle.h" -#include "mojo/public/cpp/bindings/tests/message_queue.h" -#include "mojo/public/cpp/bindings/tests/router_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace test { -namespace { - -class RouterTest : public testing::Test { - public: - RouterTest() {} - - void SetUp() override { - CreateMessagePipe(nullptr, &handle0_, &handle1_); - } - - void TearDown() override {} - - void PumpMessages() { base::RunLoop().RunUntilIdle(); } - - protected: - ScopedMessagePipeHandle handle0_; - ScopedMessagePipeHandle handle1_; - - private: - base::MessageLoop loop_; -}; - -TEST_F(RouterTest, BasicRequestResponse) { - internal::Router router0(std::move(handle0_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - internal::Router router1(std::move(handle1_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - - ResponseGenerator generator; - router1.set_incoming_receiver(&generator); - - Message request; - AllocRequestMessage(1, "hello", &request); - - MessageQueue message_queue; - base::RunLoop run_loop; - router0.AcceptWithResponder( - &request, new MessageAccumulator(&message_queue, run_loop.QuitClosure())); - - run_loop.Run(); - - EXPECT_FALSE(message_queue.IsEmpty()); - - Message response; - message_queue.Pop(&response); - - EXPECT_EQ(std::string("hello world!"), - std::string(reinterpret_cast<const char*>(response.payload()))); - - // Send a second message on the pipe. - Message request2; - AllocRequestMessage(1, "hello again", &request2); - - base::RunLoop run_loop2; - router0.AcceptWithResponder( - &request2, - new MessageAccumulator(&message_queue, run_loop2.QuitClosure())); - - run_loop2.Run(); - - EXPECT_FALSE(message_queue.IsEmpty()); - - message_queue.Pop(&response); - - EXPECT_EQ(std::string("hello again world!"), - std::string(reinterpret_cast<const char*>(response.payload()))); -} - -TEST_F(RouterTest, BasicRequestResponse_Synchronous) { - internal::Router router0(std::move(handle0_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - internal::Router router1(std::move(handle1_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - - ResponseGenerator generator; - router1.set_incoming_receiver(&generator); - - Message request; - AllocRequestMessage(1, "hello", &request); - - MessageQueue message_queue; - router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue)); - - router1.WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE); - router0.WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE); - - EXPECT_FALSE(message_queue.IsEmpty()); - - Message response; - message_queue.Pop(&response); - - EXPECT_EQ(std::string("hello world!"), - std::string(reinterpret_cast<const char*>(response.payload()))); - - // Send a second message on the pipe. - Message request2; - AllocRequestMessage(1, "hello again", &request2); - - router0.AcceptWithResponder(&request2, - new MessageAccumulator(&message_queue)); - - router1.WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE); - router0.WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE); - - EXPECT_FALSE(message_queue.IsEmpty()); - - message_queue.Pop(&response); - - EXPECT_EQ(std::string("hello again world!"), - std::string(reinterpret_cast<const char*>(response.payload()))); -} - -TEST_F(RouterTest, RequestWithNoReceiver) { - internal::Router router0(std::move(handle0_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - internal::Router router1(std::move(handle1_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - - // Without an incoming receiver set on router1, we expect router0 to observe - // an error as a result of sending a message. - - Message request; - AllocRequestMessage(1, "hello", &request); - - MessageQueue message_queue; - base::RunLoop run_loop, run_loop2; - router0.set_connection_error_handler(run_loop.QuitClosure()); - router1.set_connection_error_handler(run_loop2.QuitClosure()); - router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue)); - - run_loop.Run(); - run_loop2.Run(); - - EXPECT_TRUE(router0.encountered_error()); - EXPECT_TRUE(router1.encountered_error()); - EXPECT_TRUE(message_queue.IsEmpty()); -} - -// Tests Router using the LazyResponseGenerator. The responses will not be -// sent until after the requests have been accepted. -TEST_F(RouterTest, LazyResponses) { - internal::Router router0(std::move(handle0_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - internal::Router router1(std::move(handle1_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - - base::RunLoop run_loop; - LazyResponseGenerator generator(run_loop.QuitClosure()); - router1.set_incoming_receiver(&generator); - - Message request; - AllocRequestMessage(1, "hello", &request); - - MessageQueue message_queue; - base::RunLoop run_loop2; - router0.AcceptWithResponder( - &request, - new MessageAccumulator(&message_queue, run_loop2.QuitClosure())); - run_loop.Run(); - - // The request has been received but the response has not been sent yet. - EXPECT_TRUE(message_queue.IsEmpty()); - - // Send the response. - EXPECT_TRUE(generator.responder_is_valid()); - generator.CompleteWithResponse(); - run_loop2.Run(); - - // Check the response. - EXPECT_FALSE(message_queue.IsEmpty()); - Message response; - message_queue.Pop(&response); - EXPECT_EQ(std::string("hello world!"), - std::string(reinterpret_cast<const char*>(response.payload()))); - - // Send a second message on the pipe. - base::RunLoop run_loop3; - LazyResponseGenerator generator2(run_loop3.QuitClosure()); - - router1.set_incoming_receiver(&generator2); - Message request2; - AllocRequestMessage(1, "hello again", &request2); - - base::RunLoop run_loop4; - router0.AcceptWithResponder( - &request2, - new MessageAccumulator(&message_queue, run_loop4.QuitClosure())); - run_loop3.Run(); - - // The request has been received but the response has not been sent yet. - EXPECT_TRUE(message_queue.IsEmpty()); - - // Send the second response. - EXPECT_TRUE(generator2.responder_is_valid()); - generator2.CompleteWithResponse(); - run_loop4.Run(); - - // Check the second response. - EXPECT_FALSE(message_queue.IsEmpty()); - message_queue.Pop(&response); - EXPECT_EQ(std::string("hello again world!"), - std::string(reinterpret_cast<const char*>(response.payload()))); -} - -void ForwardErrorHandler(bool* called, const base::Closure& callback) { - *called = true; - callback.Run(); -} - -// Tests that if the receiving application destroys the responder_ without -// sending a response, then we trigger connection error at both sides. Moreover, -// both sides still appear to have a valid message pipe handle bound. -TEST_F(RouterTest, MissingResponses) { - base::RunLoop run_loop0, run_loop1; - internal::Router router0(std::move(handle0_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - bool error_handler_called0 = false; - router0.set_connection_error_handler( - base::Bind(&ForwardErrorHandler, &error_handler_called0, - run_loop0.QuitClosure())); - - internal::Router router1(std::move(handle1_), internal::FilterChain(), false, - base::ThreadTaskRunnerHandle::Get()); - bool error_handler_called1 = false; - router1.set_connection_error_handler( - base::Bind(&ForwardErrorHandler, &error_handler_called1, - run_loop1.QuitClosure())); - - base::RunLoop run_loop3; - LazyResponseGenerator generator(run_loop3.QuitClosure()); - router1.set_incoming_receiver(&generator); - router1.set_incoming_receiver(&generator); - - Message request; - AllocRequestMessage(1, "hello", &request); - - MessageQueue message_queue; - router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue)); - run_loop3.Run(); - - // The request has been received but no response has been sent. - EXPECT_TRUE(message_queue.IsEmpty()); - - // Destroy the responder MessagerReceiver but don't send any response. - generator.CompleteWithoutResponse(); - run_loop0.Run(); - run_loop1.Run(); - - // Check that no response was received. - EXPECT_TRUE(message_queue.IsEmpty()); - - // Connection error handler is called at both sides. - EXPECT_TRUE(error_handler_called0); - EXPECT_TRUE(error_handler_called1); - - // The error flag is set at both sides. - EXPECT_TRUE(router0.encountered_error()); - EXPECT_TRUE(router1.encountered_error()); - - // The message pipe handle is valid at both sides. - EXPECT_TRUE(router0.is_valid()); - EXPECT_TRUE(router1.is_valid()); -} - -TEST_F(RouterTest, LateResponse) { - // Test that things won't blow up if we try to send a message to a - // MessageReceiver, which was given to us via AcceptWithResponder, - // after the router has gone away. - - base::RunLoop run_loop; - LazyResponseGenerator generator(run_loop.QuitClosure()); - { - internal::Router router0(std::move(handle0_), internal::FilterChain(), - false, base::ThreadTaskRunnerHandle::Get()); - internal::Router router1(std::move(handle1_), internal::FilterChain(), - false, base::ThreadTaskRunnerHandle::Get()); - - router1.set_incoming_receiver(&generator); - - Message request; - AllocRequestMessage(1, "hello", &request); - - MessageQueue message_queue; - router0.AcceptWithResponder(&request, - new MessageAccumulator(&message_queue)); - - run_loop.Run(); - - EXPECT_TRUE(generator.has_responder()); - } - - EXPECT_FALSE(generator.responder_is_valid()); - generator.CompleteWithResponse(); // This should end up doing nothing. -} - -} // namespace -} // namespace test -} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc index 00a8dbf..579576f 100644 --- a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc +++ b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc @@ -38,22 +38,13 @@ bool g_dump_message_as_text = false; FooPtr MakeFoo() { std::string name("foopy"); - BarPtr bar(Bar::New()); - bar->alpha = 20; - bar->beta = 40; - bar->gamma = 60; - bar->type = Bar::Type::VERTICAL; + BarPtr bar(Bar::New(20, 40, 60, Bar::Type::VERTICAL)); std::vector<BarPtr> extra_bars(3); for (size_t i = 0; i < extra_bars.size(); ++i) { Bar::Type type = i % 2 == 0 ? Bar::Type::VERTICAL : Bar::Type::HORIZONTAL; - BarPtr bar(Bar::New()); uint8_t base = static_cast<uint8_t>(i * 100); - bar->alpha = base; - bar->beta = base + 20; - bar->gamma = base + 40; - bar->type = type; - extra_bars[i] = std::move(bar); + extra_bars[i] = Bar::New(base, base + 20, base + 40, type); } std::vector<uint8_t> data(10); @@ -84,22 +75,11 @@ FooPtr MakeFoo() { } mojo::MessagePipe pipe; - FooPtr foo(Foo::New()); - foo->name = name; - foo->x = 1; - foo->y = 2; - foo->a = false; - foo->b = true; - foo->c = false; - foo->bar = std::move(bar); - foo->extra_bars = std::move(extra_bars); - foo->data = std::move(data); - foo->source = std::move(pipe.handle1); - foo->input_streams = std::move(input_streams); - foo->output_streams = std::move(output_streams); - foo->array_of_array_of_bools = std::move(array_of_array_of_bools); - - return foo; + return Foo::New(name, 1, 2, false, true, false, std::move(bar), + std::move(extra_bars), std::move(data), + std::move(pipe.handle1), std::move(input_streams), + std::move(output_streams), std::move(array_of_array_of_bools), + base::nullopt, base::nullopt); } // Check that the given |Foo| is identical to the one made by |MakeFoo()|. @@ -310,7 +290,7 @@ class SimpleMessageReceiver : public mojo::MessageReceiverWithResponder { // the system. It receives the incoming message. ServiceImpl impl; - ServiceStub stub; + ServiceStub<> stub; stub.set_sink(&impl); return stub.Accept(message); } diff --git a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc index dcf2967..275f10f 100644 --- a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc +++ b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc @@ -8,12 +8,10 @@ #include <stddef.h> #include <utility> -#include "mojo/public/cpp/bindings/array.h" #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/lib/validation_errors.h" -#include "mojo/public/cpp/bindings/string.h" #include "mojo/public/cpp/system/message_pipe.h" #include "mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom.h" #include "mojo/public/interfaces/bindings/tests/test_unions.mojom.h" @@ -26,15 +24,16 @@ namespace { using mojo::internal::ContainerValidateParams; // Creates an array of arrays of handles (2 X 3) for testing. -Array<Array<ScopedHandle>> CreateTestNestedHandleArray() { - Array<Array<ScopedHandle>> array(2); +std::vector<base::Optional<std::vector<ScopedHandle>>> +CreateTestNestedHandleArray() { + std::vector<base::Optional<std::vector<ScopedHandle>>> array(2); for (size_t i = 0; i < array.size(); ++i) { - Array<ScopedHandle> nested_array(3); + std::vector<ScopedHandle> nested_array(3); for (size_t j = 0; j < nested_array.size(); ++j) { MessagePipe pipe; nested_array[j] = ScopedHandle::From(std::move(pipe.handle1)); } - array[i] = std::move(nested_array); + array[i].emplace(std::move(nested_array)); } return array; @@ -47,18 +46,20 @@ class SerializationWarningTest : public testing::Test { protected: template <typename T> void TestWarning(T obj, mojo::internal::ValidationError expected_warning) { + using MojomType = typename T::Struct::DataView; + warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); mojo::internal::SerializationContext context; mojo::internal::FixedBufferForTesting buf( - mojo::internal::PrepareToSerialize<T>(obj, &context)); - typename mojo::internal::MojomTypeTraits<T>::Data* data; - mojo::internal::Serialize<T>(obj, &buf, &data, &context); + mojo::internal::PrepareToSerialize<MojomType>(obj, &context)); + typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; + mojo::internal::Serialize<MojomType>(obj, &buf, &data, &context); EXPECT_EQ(expected_warning, warning_observer_.last_warning()); } - template <typename T> + template <typename MojomType, typename T> void TestArrayWarning(T obj, mojo::internal::ValidationError expected_warning, const ContainerValidateParams* validate_params) { @@ -66,9 +67,10 @@ class SerializationWarningTest : public testing::Test { mojo::internal::SerializationContext context; mojo::internal::FixedBufferForTesting buf( - mojo::internal::PrepareToSerialize<T>(obj, &context)); - typename mojo::internal::MojomTypeTraits<T>::Data* data; - mojo::internal::Serialize<T>(obj, &buf, &data, validate_params, &context); + mojo::internal::PrepareToSerialize<MojomType>(obj, &context)); + typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; + mojo::internal::Serialize<MojomType>(obj, &buf, &data, validate_params, + &context); EXPECT_EQ(expected_warning, warning_observer_.last_warning()); } @@ -76,13 +78,15 @@ class SerializationWarningTest : public testing::Test { template <typename T> void TestUnionWarning(T obj, mojo::internal::ValidationError expected_warning) { + using MojomType = typename T::Struct::DataView; + warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); mojo::internal::SerializationContext context; mojo::internal::FixedBufferForTesting buf( - mojo::internal::PrepareToSerialize<T>(obj, false, &context)); - typename mojo::internal::MojomTypeTraits<T>::Data* data; - mojo::internal::Serialize<T>(obj, &buf, &data, false, &context); + mojo::internal::PrepareToSerialize<MojomType>(obj, false, &context)); + typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; + mojo::internal::Serialize<MojomType>(obj, &buf, &data, false, &context); EXPECT_EQ(expected_warning, warning_observer_.last_warning()); } @@ -153,57 +157,64 @@ TEST_F(SerializationWarningTest, FixedArrayOfStructsInStruct) { } TEST_F(SerializationWarningTest, ArrayOfArraysOfHandles) { - Array<Array<ScopedHandle>> test_array = CreateTestNestedHandleArray(); - test_array[0] = nullptr; - test_array[1][0] = ScopedHandle(); + using MojomType = ArrayDataView<ArrayDataView<ScopedHandle>>; + auto test_array = CreateTestNestedHandleArray(); + test_array[0] = base::nullopt; + (*test_array[1])[0] = ScopedHandle(); ContainerValidateParams validate_params_0( 0, true, new ContainerValidateParams(0, true, nullptr)); - TestArrayWarning(std::move(test_array), mojo::internal::VALIDATION_ERROR_NONE, - &validate_params_0); + TestArrayWarning<MojomType>(std::move(test_array), + mojo::internal::VALIDATION_ERROR_NONE, + &validate_params_0); test_array = CreateTestNestedHandleArray(); - test_array[0] = nullptr; + test_array[0] = base::nullopt; ContainerValidateParams validate_params_1( 0, false, new ContainerValidateParams(0, true, nullptr)); - TestArrayWarning(std::move(test_array), - mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - &validate_params_1); + TestArrayWarning<MojomType>( + std::move(test_array), + mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + &validate_params_1); test_array = CreateTestNestedHandleArray(); - test_array[1][0] = ScopedHandle(); + (*test_array[1])[0] = ScopedHandle(); ContainerValidateParams validate_params_2( 0, true, new ContainerValidateParams(0, false, nullptr)); - TestArrayWarning(std::move(test_array), - mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, - &validate_params_2); + TestArrayWarning<MojomType>( + std::move(test_array), + mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, + &validate_params_2); } TEST_F(SerializationWarningTest, ArrayOfStrings) { - Array<String> test_array(3); + using MojomType = ArrayDataView<StringDataView>; + + std::vector<std::string> test_array(3); for (size_t i = 0; i < test_array.size(); ++i) test_array[i] = "hello"; ContainerValidateParams validate_params_0( 0, true, new ContainerValidateParams(0, false, nullptr)); - TestArrayWarning(std::move(test_array), mojo::internal::VALIDATION_ERROR_NONE, - &validate_params_0); + TestArrayWarning<MojomType>(std::move(test_array), + mojo::internal::VALIDATION_ERROR_NONE, + &validate_params_0); - test_array = Array<String>(3); - for (size_t i = 0; i < test_array.size(); ++i) - test_array[i] = nullptr; + std::vector<base::Optional<std::string>> optional_test_array(3); ContainerValidateParams validate_params_1( 0, false, new ContainerValidateParams(0, false, nullptr)); - TestArrayWarning(std::move(test_array), - mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - &validate_params_1); + TestArrayWarning<MojomType>( + std::move(optional_test_array), + mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + &validate_params_1); - test_array = Array<String>(2); + test_array = std::vector<std::string>(2); ContainerValidateParams validate_params_2( 3, true, new ContainerValidateParams(0, false, nullptr)); - TestArrayWarning(std::move(test_array), - mojo::internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, - &validate_params_2); + TestArrayWarning<MojomType>( + std::move(test_array), + mojo::internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, + &validate_params_2); } TEST_F(SerializationWarningTest, StructInUnion) { diff --git a/mojo/public/cpp/bindings/tests/shared_rect.h b/mojo/public/cpp/bindings/tests/shared_rect.h new file mode 100644 index 0000000..c0a4771 --- /dev/null +++ b/mojo/public/cpp/bindings/tests/shared_rect.h @@ -0,0 +1,43 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_TESTS_SHARED_RECT_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_TESTS_SHARED_RECT_H_ + +#include "base/logging.h" + +namespace mojo { +namespace test { + +// An implementation of a hypothetical Rect type specifically for consumers in +// both Chromium and Blink. +class SharedRect { + public: + SharedRect() {} + SharedRect(int x, int y, int width, int height) + : x_(x), y_(y), width_(width), height_(height) {} + + int x() const { return x_; } + void set_x(int x) { x_ = x; } + + int y() const { return y_; } + void set_y(int y) { y_ = y; } + + int width() const { return width_; } + void set_width(int width) { width_ = width; } + + int height() const { return height_; } + void set_height(int height) { height_ = height; } + + private: + int x_ = 0; + int y_ = 0; + int width_ = 0; + int height_ = 0; +}; + +} // namespace test +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_TESTS_SHARED_RECT_H_ diff --git a/mojo/public/cpp/bindings/tests/shared_rect_traits.h b/mojo/public/cpp/bindings/tests/shared_rect_traits.h new file mode 100644 index 0000000..bbf04d5 --- /dev/null +++ b/mojo/public/cpp/bindings/tests/shared_rect_traits.h @@ -0,0 +1,33 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_TESTS_SHARED_RECT_TRAITS_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_TESTS_SHARED_RECT_TRAITS_H_ + +#include "mojo/public/cpp/bindings/struct_traits.h" +#include "mojo/public/cpp/bindings/tests/shared_rect.h" +#include "mojo/public/interfaces/bindings/tests/rect.mojom-shared.h" + +namespace mojo { + +template <> +struct StructTraits<test::SharedTypemappedRectDataView, test::SharedRect> { + static int x(const test::SharedRect& r) { return r.x(); } + static int y(const test::SharedRect& r) { return r.y(); } + static int width(const test::SharedRect& r) { return r.width(); } + static int height(const test::SharedRect& r) { return r.height(); } + + static bool Read(test::SharedTypemappedRectDataView r, + test::SharedRect* out) { + out->set_x(r.x()); + out->set_y(r.y()); + out->set_width(r.width()); + out->set_height(r.height()); + return true; + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_TESTS_SHARED_RECT_TRAITS_H_ diff --git a/mojo/public/cpp/bindings/tests/stl_converters_unittest.cc b/mojo/public/cpp/bindings/tests/stl_converters_unittest.cc deleted file mode 100644 index 92a31b3..0000000 --- a/mojo/public/cpp/bindings/tests/stl_converters_unittest.cc +++ /dev/null @@ -1,93 +0,0 @@ -// 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 "mojo/public/cpp/bindings/stl_converters.h" - -#include <map> -#include <string> -#include <vector> - -#include "mojo/public/cpp/bindings/array.h" -#include "mojo/public/cpp/bindings/map.h" -#include "mojo/public/cpp/bindings/string.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 { - -using STLConvertersTest = testing::Test; - -TEST_F(STLConvertersTest, AvoidUnnecessaryCopies) { - Array<CopyableType> mojo_array(1); - std::vector<CopyableType> stl_vector = UnwrapToSTLType(std::move(mojo_array)); - ASSERT_EQ(1u, stl_vector.size()); - ASSERT_FALSE(stl_vector[0].copied()); - Array<CopyableType> mojo_array2 = WrapSTLType(std::move(stl_vector)); - ASSERT_EQ(1u, mojo_array2.size()); - ASSERT_FALSE(mojo_array2[0].copied()); - - Map<int32_t, CopyableType> mojo_map; - mojo_map.insert(42, CopyableType()); - mojo_map[42].ResetCopied(); - std::map<int32_t, CopyableType> stl_map = - UnwrapToSTLType(std::move(mojo_map)); - ASSERT_EQ(1u, stl_map.size()); - ASSERT_FALSE(stl_map[42].copied()); - Map<int32_t, CopyableType> mojo_map2 = WrapSTLType(std::move(stl_map)); - ASSERT_EQ(1u, mojo_map2.size()); - ASSERT_FALSE(mojo_map2[42].copied()); -} - -TEST_F(STLConvertersTest, RecursiveConversion) { - Array<Map<String, Array<int32_t>>> mojo_obj(2); - mojo_obj[0] = nullptr; - mojo_obj[1]["hello"].push_back(123); - mojo_obj[1]["hello"].push_back(456); - - std::vector<std::map<std::string, std::vector<int32_t>>> stl_obj = - UnwrapToSTLType(std::move(mojo_obj)); - - ASSERT_EQ(2u, stl_obj.size()); - ASSERT_TRUE(stl_obj[0].empty()); - ASSERT_EQ(1u, stl_obj[1].size()); - ASSERT_EQ(2u, stl_obj[1]["hello"].size()); - ASSERT_EQ(123, stl_obj[1]["hello"][0]); - ASSERT_EQ(456, stl_obj[1]["hello"][1]); - - Array<Map<String, Array<int32_t>>> mojo_obj2 = - WrapSTLType(std::move(stl_obj)); - - ASSERT_EQ(2u, mojo_obj2.size()); - ASSERT_EQ(0u, mojo_obj2[0].size()); - // The null flag has been lost when converted to std::map. - ASSERT_FALSE(mojo_obj2[0].is_null()); - ASSERT_EQ(1u, mojo_obj2[1].size()); - ASSERT_EQ(2u, mojo_obj2[1]["hello"].size()); - ASSERT_EQ(123, mojo_obj2[1]["hello"][0]); - ASSERT_EQ(456, mojo_obj2[1]["hello"][1]); -} - -TEST_F(STLConvertersTest, StopsAtMojoStruct) { - Array<NamedRegionPtr> mojo_obj(1); - mojo_obj[0] = NamedRegion::New(); - mojo_obj[0]->name.emplace("hello"); - mojo_obj[0]->rects.emplace(3); - - std::vector<NamedRegionPtr> stl_obj = UnwrapToSTLType(std::move(mojo_obj)); - - ASSERT_EQ(1u, stl_obj.size()); - ASSERT_EQ("hello", stl_obj[0]->name.value()); - ASSERT_EQ(3u, stl_obj[0]->rects->size()); - - Array<NamedRegionPtr> mojo_obj2 = WrapSTLType(std::move(stl_obj)); - - ASSERT_EQ(1u, mojo_obj2.size()); - ASSERT_EQ("hello", mojo_obj2[0]->name.value()); - ASSERT_EQ(3u, mojo_obj2[0]->rects->size()); -} - -} // namespace test -} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/string_unittest.cc b/mojo/public/cpp/bindings/tests/string_unittest.cc deleted file mode 100644 index 13486ae..0000000 --- a/mojo/public/cpp/bindings/tests/string_unittest.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2014 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 "mojo/public/cpp/bindings/string.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace test { - -namespace { -const char* kHelloWorld = "hello world"; -} // namespace - -TEST(StringTest, DefaultIsNotNull) { - String s; - EXPECT_FALSE(s.is_null()); -} - -TEST(StringTest, ConstructedWithNULL) { - String s(nullptr); - EXPECT_TRUE(s.is_null()); -} - -TEST(StringTest, ConstructedWithNullCharPointer) { - const char* null = nullptr; - String s(null); - EXPECT_TRUE(s.is_null()); -} - -TEST(StringTest, AssignedNULL) { - String s(""); - EXPECT_FALSE(s.is_null()); - s = nullptr; - EXPECT_TRUE(s.is_null()); -} - -TEST(StringTest, Empty) { - String s(""); - EXPECT_FALSE(s.is_null()); - EXPECT_TRUE(s.get().empty()); -} - -TEST(StringTest, Basic) { - String s(kHelloWorld); - EXPECT_EQ(std::string(kHelloWorld), s.get()); -} - -TEST(StringTest, Assignment) { - String s(kHelloWorld); - String t = s; // Makes a copy. - EXPECT_FALSE(t.is_null()); - EXPECT_EQ(std::string(kHelloWorld), t.get()); - EXPECT_FALSE(s.is_null()); -} - -TEST(StringTest, Equality) { - String s(kHelloWorld); - String t(kHelloWorld); - EXPECT_EQ(s, t); - EXPECT_TRUE(s == s); - EXPECT_FALSE(s != s); - EXPECT_TRUE(s == t); - EXPECT_FALSE(s != t); - EXPECT_TRUE(kHelloWorld == s); - EXPECT_TRUE(s == kHelloWorld); - EXPECT_TRUE("not" != s); - EXPECT_FALSE("not" == s); - EXPECT_TRUE(s != "not"); - EXPECT_FALSE(s == "not"); - - // Test null strings. - String n1; - String n2; - EXPECT_TRUE(n1 == n1); - EXPECT_FALSE(n1 != n2); - EXPECT_TRUE(n1 == n2); - EXPECT_FALSE(n1 != n2); - EXPECT_TRUE(n1 != s); - EXPECT_FALSE(n1 == s); - EXPECT_TRUE(s != n1); - EXPECT_FALSE(s == n1); -} - -TEST(StringTest, LessThanNullness) { - String null; - String null2; - EXPECT_FALSE(null < null2); - EXPECT_FALSE(null2 < null); - - String real("real"); - EXPECT_TRUE(null < real); - EXPECT_FALSE(real < null); -} - -TEST(StringTest, MoveConstructors) { - std::string std_str(kHelloWorld); - - String str1(std::move(std_str)); - EXPECT_TRUE(kHelloWorld == str1); - - String str2(std::move(str1)); - EXPECT_TRUE(kHelloWorld == str2); - EXPECT_TRUE(str1.is_null()); -} - -TEST(StringTest, MoveAssignments) { - std::string std_str(kHelloWorld); - - String str1; - str1 = std::move(std_str); - EXPECT_TRUE(kHelloWorld == str1); - - String str2; - str2 = std::move(str1); - EXPECT_TRUE(kHelloWorld == str2); - EXPECT_TRUE(str1.is_null()); -} - -TEST(StringTest, Storage) { - String str(kHelloWorld); - - EXPECT_TRUE(kHelloWorld == str.storage()); - - std::string storage = str.PassStorage(); - EXPECT_TRUE(str.is_null()); - EXPECT_TRUE(kHelloWorld == storage); -} - -} // namespace test -} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc index 583dc46..4c06267 100644 --- a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc +++ b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc @@ -5,6 +5,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "mojo/public/cpp/bindings/binding_set.h" @@ -70,6 +71,11 @@ class ChromiumRectServiceImpl : public RectService { callback.Run(largest_rect_); } + void PassSharedRect(const SharedRect& r, + const PassSharedRectCallback& callback) override { + callback.Run(r); + } + private: RectChromium largest_rect_; }; @@ -93,6 +99,11 @@ class BlinkRectServiceImpl : public blink::RectService { callback.Run(largest_rect_); } + void PassSharedRect(const SharedRect& r, + const PassSharedRectCallback& callback) override { + callback.Run(r); + } + private: RectBlink largest_rect_; }; @@ -134,9 +145,21 @@ class StructTraitsTest : public testing::Test, callback.Run(s); } - void EchoPassByValueStructWithTraits( - PassByValueStructWithTraitsImpl s, - const EchoPassByValueStructWithTraitsCallback& callback) override { + void EchoTrivialStructWithTraits( + TrivialStructWithTraitsImpl s, + const EchoTrivialStructWithTraitsCallback& callback) override { + callback.Run(s); + } + + void EchoMoveOnlyStructWithTraits( + MoveOnlyStructWithTraitsImpl s, + const EchoMoveOnlyStructWithTraitsCallback& callback) override { + callback.Run(std::move(s)); + } + + void EchoNullableMoveOnlyStructWithTraits( + base::Optional<MoveOnlyStructWithTraitsImpl> s, + const EchoNullableMoveOnlyStructWithTraitsCallback& callback) override { callback.Run(std::move(s)); } @@ -145,12 +168,25 @@ class StructTraitsTest : public testing::Test, callback.Run(e); } - void EchoStructWithTraitsForUniquePtrTest( + void EchoStructWithTraitsForUniquePtr( std::unique_ptr<int> e, - const EchoStructWithTraitsForUniquePtrTestCallback& callback) override { + const EchoStructWithTraitsForUniquePtrCallback& callback) override { callback.Run(std::move(e)); } + void EchoNullableStructWithTraitsForUniquePtr( + std::unique_ptr<int> e, + const EchoNullableStructWithTraitsForUniquePtrCallback& callback) + override { + callback.Run(std::move(e)); + } + + void EchoUnionWithTraits( + std::unique_ptr<test::UnionWithTraitsBase> u, + const EchoUnionWithTraitsCallback& callback) override { + callback.Run(std::move(u)); + } + base::MessageLoop loop_; ChromiumRectServiceImpl chromium_service_; @@ -166,7 +202,7 @@ class StructTraitsTest : public testing::Test, TEST_F(StructTraitsTest, ChromiumProxyToChromiumService) { RectServicePtr chromium_proxy; - BindToChromiumService(GetProxy(&chromium_proxy)); + BindToChromiumService(MakeRequest(&chromium_proxy)); { base::RunLoop loop; chromium_proxy->AddRect(RectChromium(1, 1, 4, 5)); @@ -175,11 +211,18 @@ TEST_F(StructTraitsTest, ChromiumProxyToChromiumService) { ExpectResult(RectChromium(1, 1, 4, 5), loop.QuitClosure())); loop.Run(); } + { + base::RunLoop loop; + chromium_proxy->PassSharedRect( + {1, 2, 3, 4}, + ExpectResult(SharedRect({1, 2, 3, 4}), loop.QuitClosure())); + loop.Run(); + } } TEST_F(StructTraitsTest, ChromiumToBlinkService) { RectServicePtr chromium_proxy; - BindToBlinkService(GetProxy(&chromium_proxy)); + BindToBlinkService(MakeRequest(&chromium_proxy)); { base::RunLoop loop; chromium_proxy->AddRect(RectChromium(1, 1, 4, 5)); @@ -188,6 +231,13 @@ TEST_F(StructTraitsTest, ChromiumToBlinkService) { ExpectResult(RectChromium(2, 2, 5, 5), loop.QuitClosure())); loop.Run(); } + { + base::RunLoop loop; + chromium_proxy->PassSharedRect( + {1, 2, 3, 4}, + ExpectResult(SharedRect({1, 2, 3, 4}), loop.QuitClosure())); + loop.Run(); + } // The Blink service should drop our connection because RectBlink's // deserializer rejects negative origins. { @@ -202,7 +252,7 @@ TEST_F(StructTraitsTest, ChromiumToBlinkService) { TEST_F(StructTraitsTest, BlinkProxyToBlinkService) { blink::RectServicePtr blink_proxy; - BindToBlinkService(GetProxy(&blink_proxy)); + BindToBlinkService(MakeRequest(&blink_proxy)); { base::RunLoop loop; blink_proxy->AddRect(RectBlink(1, 1, 4, 5)); @@ -211,11 +261,18 @@ TEST_F(StructTraitsTest, BlinkProxyToBlinkService) { ExpectResult(RectBlink(10, 10, 20, 20), loop.QuitClosure())); loop.Run(); } + { + base::RunLoop loop; + blink_proxy->PassSharedRect( + {4, 3, 2, 1}, + ExpectResult(SharedRect({4, 3, 2, 1}), loop.QuitClosure())); + loop.Run(); + } } TEST_F(StructTraitsTest, BlinkProxyToChromiumService) { blink::RectServicePtr blink_proxy; - BindToChromiumService(GetProxy(&blink_proxy)); + BindToChromiumService(MakeRequest(&blink_proxy)); { base::RunLoop loop; blink_proxy->AddRect(RectBlink(1, 1, 4, 5)); @@ -224,6 +281,13 @@ TEST_F(StructTraitsTest, BlinkProxyToChromiumService) { ExpectResult(RectBlink(1, 1, 4, 5), loop.QuitClosure())); loop.Run(); } + { + base::RunLoop loop; + blink_proxy->PassSharedRect( + {4, 3, 2, 1}, + ExpectResult(SharedRect({4, 3, 2, 1}), loop.QuitClosure())); + loop.Run(); + } } void ExpectStructWithTraits(const StructWithTraitsImpl& expected, @@ -249,6 +313,8 @@ TEST_F(StructTraitsTest, EchoStructWithTraits) { input.set_uint64(42); input.set_string("hello world!"); input.get_mutable_string_array().assign({"hello", "world!"}); + input.get_mutable_string_set().insert("hello"); + input.get_mutable_string_set().insert("world!"); input.get_mutable_struct().value = 42; input.get_mutable_struct_array().resize(2); input.get_mutable_struct_array()[0].value = 1; @@ -274,24 +340,44 @@ TEST_F(StructTraitsTest, CloneStructWithTraitsContainer) { EXPECT_EQ(42u, cloned_container->f_struct.get_uint64()); } +void ExpectTrivialStructWithTraits(TrivialStructWithTraitsImpl expected, + const base::Closure& closure, + TrivialStructWithTraitsImpl passed) { + EXPECT_EQ(expected.value, passed.value); + closure.Run(); +} + +TEST_F(StructTraitsTest, EchoTrivialStructWithTraits) { + TrivialStructWithTraitsImpl input; + input.value = 42; + + base::RunLoop loop; + TraitsTestServicePtr proxy = GetTraitsTestProxy(); + + proxy->EchoTrivialStructWithTraits( + input, + base::Bind(&ExpectTrivialStructWithTraits, input, loop.QuitClosure())); + loop.Run(); +} + void CaptureMessagePipe(ScopedMessagePipeHandle* storage, const base::Closure& closure, - PassByValueStructWithTraitsImpl passed) { + MoveOnlyStructWithTraitsImpl passed) { storage->reset(MessagePipeHandle( passed.get_mutable_handle().release().value())); closure.Run(); } -TEST_F(StructTraitsTest, EchoPassByValueStructWithTraits) { +TEST_F(StructTraitsTest, EchoMoveOnlyStructWithTraits) { MessagePipe mp; - PassByValueStructWithTraitsImpl input; + MoveOnlyStructWithTraitsImpl input; input.get_mutable_handle().reset(mp.handle0.release()); base::RunLoop loop; TraitsTestServicePtr proxy = GetTraitsTestProxy(); ScopedMessagePipeHandle received; - proxy->EchoPassByValueStructWithTraits( + proxy->EchoMoveOnlyStructWithTraits( std::move(input), base::Bind(&CaptureMessagePipe, &received, loop.QuitClosure())); loop.Run(); @@ -317,6 +403,27 @@ TEST_F(StructTraitsTest, EchoPassByValueStructWithTraits) { EXPECT_STREQ(kHello, buffer); } +void CaptureNullableMoveOnlyStructWithTraitsImpl( + base::Optional<MoveOnlyStructWithTraitsImpl>* storage, + const base::Closure& closure, + base::Optional<MoveOnlyStructWithTraitsImpl> passed) { + *storage = std::move(passed); + closure.Run(); +} + +TEST_F(StructTraitsTest, EchoNullableMoveOnlyStructWithTraits) { + base::RunLoop loop; + TraitsTestServicePtr proxy = GetTraitsTestProxy(); + + base::Optional<MoveOnlyStructWithTraitsImpl> received; + proxy->EchoNullableMoveOnlyStructWithTraits( + base::nullopt, base::Bind(&CaptureNullableMoveOnlyStructWithTraitsImpl, + &received, loop.QuitClosure())); + loop.Run(); + + EXPECT_FALSE(received); +} + void ExpectEnumWithTraits(EnumWithTraitsImpl expected_value, const base::Closure& closure, EnumWithTraitsImpl value) { @@ -342,7 +449,9 @@ TEST_F(StructTraitsTest, SerializeStructWithTraits) { input.set_uint32(7); input.set_uint64(42); input.set_string("hello world!"); - input.get_mutable_string_array().assign({"hello", "world!"}); + input.get_mutable_string_array().assign({ "hello", "world!" }); + input.get_mutable_string_set().insert("hello"); + input.get_mutable_string_set().insert("world!"); input.get_mutable_struct().value = 42; input.get_mutable_struct_array().resize(2); input.get_mutable_struct_array()[0].value = 1; @@ -350,7 +459,7 @@ TEST_F(StructTraitsTest, SerializeStructWithTraits) { input.get_mutable_struct_map()["hello"] = NestedStructWithTraitsImpl(1024); input.get_mutable_struct_map()["world"] = NestedStructWithTraitsImpl(2048); - mojo::Array<uint8_t> data = StructWithTraits::Serialize(&input); + auto data = StructWithTraits::Serialize(&input); StructWithTraitsImpl output; ASSERT_TRUE(StructWithTraits::Deserialize(std::move(data), &output)); @@ -360,26 +469,84 @@ TEST_F(StructTraitsTest, SerializeStructWithTraits) { EXPECT_EQ(input.get_uint64(), output.get_uint64()); EXPECT_EQ(input.get_string(), output.get_string()); EXPECT_EQ(input.get_string_array(), output.get_string_array()); + EXPECT_EQ(input.get_string_set(), output.get_string_set()); EXPECT_EQ(input.get_struct(), output.get_struct()); EXPECT_EQ(input.get_struct_array(), output.get_struct_array()); EXPECT_EQ(input.get_struct_map(), output.get_struct_map()); } -void ExpectUniquePtr(int expected, +void ExpectUniquePtr(std::unique_ptr<int> expected, const base::Closure& closure, std::unique_ptr<int> value) { - EXPECT_EQ(expected, *value); + ASSERT_EQ(!expected, !value); + if (expected) + EXPECT_EQ(*expected, *value); closure.Run(); } TEST_F(StructTraitsTest, TypemapUniquePtr) { - base::RunLoop loop; TraitsTestServicePtr proxy = GetTraitsTestProxy(); - proxy->EchoStructWithTraitsForUniquePtrTest( - base::MakeUnique<int>(12345), - base::Bind(&ExpectUniquePtr, 12345, loop.QuitClosure())); - loop.Run(); + { + base::RunLoop loop; + proxy->EchoStructWithTraitsForUniquePtr( + base::MakeUnique<int>(12345), + base::Bind(&ExpectUniquePtr, base::Passed(base::MakeUnique<int>(12345)), + loop.QuitClosure())); + loop.Run(); + } + { + base::RunLoop loop; + proxy->EchoNullableStructWithTraitsForUniquePtr( + nullptr, base::Bind(&ExpectUniquePtr, nullptr, loop.QuitClosure())); + loop.Run(); + } +} + +TEST_F(StructTraitsTest, EchoUnionWithTraits) { + TraitsTestServicePtr proxy = GetTraitsTestProxy(); + + { + std::unique_ptr<test::UnionWithTraitsBase> input( + new test::UnionWithTraitsInt32(1234)); + base::RunLoop loop; + proxy->EchoUnionWithTraits( + std::move(input), + base::Bind( + [](const base::Closure& quit_closure, + std::unique_ptr<test::UnionWithTraitsBase> passed) { + ASSERT_EQ(test::UnionWithTraitsBase::Type::INT32, passed->type()); + EXPECT_EQ(1234, + static_cast<test::UnionWithTraitsInt32*>(passed.get()) + ->value()); + quit_closure.Run(); + + }, + loop.QuitClosure())); + loop.Run(); + } + + { + std::unique_ptr<test::UnionWithTraitsBase> input( + new test::UnionWithTraitsStruct(4321)); + base::RunLoop loop; + proxy->EchoUnionWithTraits( + std::move(input), + base::Bind( + [](const base::Closure& quit_closure, + std::unique_ptr<test::UnionWithTraitsBase> passed) { + ASSERT_EQ(test::UnionWithTraitsBase::Type::STRUCT, + passed->type()); + EXPECT_EQ(4321, + static_cast<test::UnionWithTraitsStruct*>(passed.get()) + ->get_struct() + .value); + quit_closure.Run(); + + }, + loop.QuitClosure())); + loop.Run(); + } } } // namespace test diff --git a/mojo/public/cpp/bindings/tests/struct_unittest.cc b/mojo/public/cpp/bindings/tests/struct_unittest.cc index 76b4cce..13ba507 100644 --- a/mojo/public/cpp/bindings/tests/struct_unittest.cc +++ b/mojo/public/cpp/bindings/tests/struct_unittest.cc @@ -17,12 +17,7 @@ namespace test { namespace { RectPtr MakeRect(int32_t factor = 1) { - RectPtr rect(Rect::New()); - rect->x = 1 * factor; - rect->y = 2 * factor; - rect->width = 10 * factor; - rect->height = 20 * factor; - return rect; + return Rect::New(1 * factor, 2 * factor, 10 * factor, 20 * factor); } void CheckRect(const Rect& rect, int32_t factor = 1) { @@ -33,31 +28,28 @@ void CheckRect(const Rect& rect, int32_t factor = 1) { } MultiVersionStructPtr MakeMultiVersionStruct() { - MultiVersionStructPtr output(MultiVersionStruct::New()); - output->f_int32 = 123; - output->f_rect = MakeRect(5); - output->f_string.emplace("hello"); - output->f_array.emplace(3); - (*output->f_array)[0] = 10; - (*output->f_array)[1] = 9; - (*output->f_array)[2] = 8; MessagePipe pipe; - output->f_message_pipe = std::move(pipe.handle0); - output->f_int16 = 42; - - return output; + return MultiVersionStruct::New(123, MakeRect(5), std::string("hello"), + std::vector<int8_t>{10, 9, 8}, + std::move(pipe.handle0), false, 42); } template <typename U, typename T> U SerializeAndDeserialize(T input) { - using InputDataType = typename mojo::internal::MojomTypeTraits<T>::Data*; - using OutputDataType = typename mojo::internal::MojomTypeTraits<U>::Data*; + using InputMojomType = typename T::Struct::DataView; + using OutputMojomType = typename U::Struct::DataView; + + using InputDataType = + typename mojo::internal::MojomTypeTraits<InputMojomType>::Data*; + using OutputDataType = + typename mojo::internal::MojomTypeTraits<OutputMojomType>::Data*; mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<T>(input, &context); + size_t size = + mojo::internal::PrepareToSerialize<InputMojomType>(input, &context); mojo::internal::FixedBufferForTesting buf(size + 32); InputDataType data; - mojo::internal::Serialize<T>(input, &buf, &data, &context); + mojo::internal::Serialize<InputMojomType>(input, &buf, &data, &context); // Set the subsequent area to a special value, so that we can find out if we // mistakenly access the area. @@ -67,7 +59,7 @@ U SerializeAndDeserialize(T input) { OutputDataType output_data = reinterpret_cast<OutputDataType>(data); U output; - mojo::internal::Deserialize<U>(output_data, &output, &context); + mojo::internal::Deserialize<OutputMojomType>(output_data, &output, &context); return std::move(output); } @@ -131,15 +123,15 @@ TEST_F(StructTest, Clone) { TEST_F(StructTest, Serialization_Basic) { RectPtr rect(MakeRect()); - size_t size = mojo::internal::PrepareToSerialize<RectPtr>(rect, nullptr); + size_t size = mojo::internal::PrepareToSerialize<RectDataView>(rect, nullptr); EXPECT_EQ(8U + 16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::Rect_Data* data; - mojo::internal::Serialize<RectPtr>(rect, &buf, &data, nullptr); + mojo::internal::Serialize<RectDataView>(rect, &buf, &data, nullptr); RectPtr rect2; - mojo::internal::Deserialize<RectPtr>(data, &rect2, nullptr); + mojo::internal::Deserialize<RectDataView>(data, &rect2, nullptr); CheckRect(*rect2); } @@ -160,19 +152,18 @@ TEST_F(StructTest, Construction_StructPointers) { // Serialization test of a struct with struct pointers. TEST_F(StructTest, Serialization_StructPointers) { - RectPairPtr pair(RectPair::New()); - pair->first = MakeRect(); - pair->second = MakeRect(); + RectPairPtr pair(RectPair::New(MakeRect(), MakeRect())); - size_t size = mojo::internal::PrepareToSerialize<RectPairPtr>(pair, nullptr); + size_t size = + mojo::internal::PrepareToSerialize<RectPairDataView>(pair, nullptr); EXPECT_EQ(8U + 16U + 2 * (8U + 16U), size); mojo::internal::FixedBufferForTesting buf(size); internal::RectPair_Data* data; - mojo::internal::Serialize<RectPairPtr>(pair, &buf, &data, nullptr); + mojo::internal::Serialize<RectPairDataView>(pair, &buf, &data, nullptr); RectPairPtr pair2; - mojo::internal::Deserialize<RectPairPtr>(data, &pair2, nullptr); + mojo::internal::Deserialize<RectPairDataView>(data, &pair2, nullptr); CheckRect(*pair2->first); CheckRect(*pair2->second); @@ -180,14 +171,15 @@ TEST_F(StructTest, Serialization_StructPointers) { // Serialization test of a struct with an array member. TEST_F(StructTest, Serialization_ArrayPointers) { - NamedRegionPtr region(NamedRegion::New()); - region->name.emplace("region"); - region->rects.emplace(4); - for (size_t i = 0; i < region->rects->size(); ++i) - (*region->rects)[i] = MakeRect(static_cast<int32_t>(i) + 1); + std::vector<RectPtr> rects; + for (size_t i = 0; i < 4; ++i) + rects.push_back(MakeRect(static_cast<int32_t>(i) + 1)); + + NamedRegionPtr region( + NamedRegion::New(std::string("region"), std::move(rects))); size_t size = - mojo::internal::PrepareToSerialize<NamedRegionPtr>(region, nullptr); + mojo::internal::PrepareToSerialize<NamedRegionDataView>(region, nullptr); EXPECT_EQ(8U + // header 8U + // name pointer 8U + // rects pointer @@ -201,10 +193,10 @@ TEST_F(StructTest, Serialization_ArrayPointers) { mojo::internal::FixedBufferForTesting buf(size); internal::NamedRegion_Data* data; - mojo::internal::Serialize<NamedRegionPtr>(region, &buf, &data, nullptr); + mojo::internal::Serialize<NamedRegionDataView>(region, &buf, &data, nullptr); NamedRegionPtr region2; - mojo::internal::Deserialize<NamedRegionPtr>(data, ®ion2, nullptr); + mojo::internal::Deserialize<NamedRegionDataView>(data, ®ion2, nullptr); EXPECT_EQ("region", *region2->name); @@ -220,7 +212,7 @@ TEST_F(StructTest, Serialization_NullArrayPointers) { EXPECT_FALSE(region->rects); size_t size = - mojo::internal::PrepareToSerialize<NamedRegionPtr>(region, nullptr); + mojo::internal::PrepareToSerialize<NamedRegionDataView>(region, nullptr); EXPECT_EQ(8U + // header 8U + // name pointer 8U, // rects pointer @@ -228,10 +220,10 @@ TEST_F(StructTest, Serialization_NullArrayPointers) { mojo::internal::FixedBufferForTesting buf(size); internal::NamedRegion_Data* data; - mojo::internal::Serialize<NamedRegionPtr>(region, &buf, &data, nullptr); + mojo::internal::Serialize<NamedRegionDataView>(region, &buf, &data, nullptr); NamedRegionPtr region2; - mojo::internal::Deserialize<NamedRegionPtr>(data, ®ion2, nullptr); + mojo::internal::Deserialize<NamedRegionDataView>(data, ®ion2, nullptr); EXPECT_FALSE(region2->name); EXPECT_FALSE(region2->rects); @@ -240,10 +232,8 @@ TEST_F(StructTest, Serialization_NullArrayPointers) { // Tests deserializing structs as a newer version. TEST_F(StructTest, Versioning_OldToNew) { { - MultiVersionStructV0Ptr input(MultiVersionStructV0::New()); - input->f_int32 = 123; - MultiVersionStructPtr expected_output(MultiVersionStruct::New()); - expected_output->f_int32 = 123; + MultiVersionStructV0Ptr input(MultiVersionStructV0::New(123)); + MultiVersionStructPtr expected_output(MultiVersionStruct::New(123)); MultiVersionStructPtr output = SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input)); @@ -252,12 +242,9 @@ TEST_F(StructTest, Versioning_OldToNew) { } { - MultiVersionStructV1Ptr input(MultiVersionStructV1::New()); - input->f_int32 = 123; - input->f_rect = MakeRect(5); - MultiVersionStructPtr expected_output(MultiVersionStruct::New()); - expected_output->f_int32 = 123; - expected_output->f_rect = MakeRect(5); + MultiVersionStructV1Ptr input(MultiVersionStructV1::New(123, MakeRect(5))); + MultiVersionStructPtr expected_output( + MultiVersionStruct::New(123, MakeRect(5))); MultiVersionStructPtr output = SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input)); @@ -266,14 +253,10 @@ TEST_F(StructTest, Versioning_OldToNew) { } { - MultiVersionStructV3Ptr input(MultiVersionStructV3::New()); - input->f_int32 = 123; - input->f_rect = MakeRect(5); - input->f_string.emplace("hello"); - MultiVersionStructPtr expected_output(MultiVersionStruct::New()); - expected_output->f_int32 = 123; - expected_output->f_rect = MakeRect(5); - expected_output->f_string.emplace("hello"); + MultiVersionStructV3Ptr input( + MultiVersionStructV3::New(123, MakeRect(5), std::string("hello"))); + MultiVersionStructPtr expected_output( + MultiVersionStruct::New(123, MakeRect(5), std::string("hello"))); MultiVersionStructPtr output = SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input)); @@ -282,22 +265,10 @@ TEST_F(StructTest, Versioning_OldToNew) { } { - MultiVersionStructV5Ptr input(MultiVersionStructV5::New()); - input->f_int32 = 123; - input->f_rect = MakeRect(5); - input->f_string.emplace("hello"); - input->f_array.emplace(3); - (*input->f_array)[0] = 10; - (*input->f_array)[1] = 9; - (*input->f_array)[2] = 8; - MultiVersionStructPtr expected_output(MultiVersionStruct::New()); - expected_output->f_int32 = 123; - expected_output->f_rect = MakeRect(5); - expected_output->f_string.emplace("hello"); - expected_output->f_array.emplace(3); - (*expected_output->f_array)[0] = 10; - (*expected_output->f_array)[1] = 9; - (*expected_output->f_array)[2] = 8; + MultiVersionStructV5Ptr input(MultiVersionStructV5::New( + 123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8})); + MultiVersionStructPtr expected_output(MultiVersionStruct::New( + 123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8})); MultiVersionStructPtr output = SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input)); @@ -306,25 +277,13 @@ TEST_F(StructTest, Versioning_OldToNew) { } { - MultiVersionStructV7Ptr input(MultiVersionStructV7::New()); - input->f_int32 = 123; - input->f_rect = MakeRect(5); - input->f_string.emplace("hello"); - input->f_array.emplace(3); - (*input->f_array)[0] = 10; - (*input->f_array)[1] = 9; - (*input->f_array)[2] = 8; MessagePipe pipe; - input->f_message_pipe = std::move(pipe.handle0); - - MultiVersionStructPtr expected_output(MultiVersionStruct::New()); - expected_output->f_int32 = 123; - expected_output->f_rect = MakeRect(5); - expected_output->f_string.emplace("hello"); - expected_output->f_array.emplace(3); - (*expected_output->f_array)[0] = 10; - (*expected_output->f_array)[1] = 9; - (*expected_output->f_array)[2] = 8; + MultiVersionStructV7Ptr input(MultiVersionStructV7::New( + 123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8}, + std::move(pipe.handle0), false)); + + MultiVersionStructPtr expected_output(MultiVersionStruct::New( + 123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8})); // Save the raw handle value separately so that we can compare later. MojoHandle expected_handle = input->f_message_pipe.get().value(); @@ -341,14 +300,8 @@ TEST_F(StructTest, Versioning_OldToNew) { TEST_F(StructTest, Versioning_NewToOld) { { MultiVersionStructPtr input = MakeMultiVersionStruct(); - MultiVersionStructV7Ptr expected_output(MultiVersionStructV7::New()); - expected_output->f_int32 = 123; - expected_output->f_rect = MakeRect(5); - expected_output->f_string.emplace("hello"); - expected_output->f_array.emplace(3); - (*expected_output->f_array)[0] = 10; - (*expected_output->f_array)[1] = 9; - (*expected_output->f_array)[2] = 8; + MultiVersionStructV7Ptr expected_output(MultiVersionStructV7::New( + 123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8})); // Save the raw handle value separately so that we can compare later. MojoHandle expected_handle = input->f_message_pipe.get().value(); @@ -362,14 +315,8 @@ TEST_F(StructTest, Versioning_NewToOld) { { MultiVersionStructPtr input = MakeMultiVersionStruct(); - MultiVersionStructV5Ptr expected_output(MultiVersionStructV5::New()); - expected_output->f_int32 = 123; - expected_output->f_rect = MakeRect(5); - expected_output->f_string.emplace("hello"); - expected_output->f_array.emplace(3); - (*expected_output->f_array)[0] = 10; - (*expected_output->f_array)[1] = 9; - (*expected_output->f_array)[2] = 8; + MultiVersionStructV5Ptr expected_output(MultiVersionStructV5::New( + 123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8})); MultiVersionStructV5Ptr output = SerializeAndDeserialize<MultiVersionStructV5Ptr>(std::move(input)); @@ -379,10 +326,8 @@ TEST_F(StructTest, Versioning_NewToOld) { { MultiVersionStructPtr input = MakeMultiVersionStruct(); - MultiVersionStructV3Ptr expected_output(MultiVersionStructV3::New()); - expected_output->f_int32 = 123; - expected_output->f_rect = MakeRect(5); - expected_output->f_string.emplace("hello"); + MultiVersionStructV3Ptr expected_output( + MultiVersionStructV3::New(123, MakeRect(5), std::string("hello"))); MultiVersionStructV3Ptr output = SerializeAndDeserialize<MultiVersionStructV3Ptr>(std::move(input)); @@ -392,9 +337,8 @@ TEST_F(StructTest, Versioning_NewToOld) { { MultiVersionStructPtr input = MakeMultiVersionStruct(); - MultiVersionStructV1Ptr expected_output(MultiVersionStructV1::New()); - expected_output->f_int32 = 123; - expected_output->f_rect = MakeRect(5); + MultiVersionStructV1Ptr expected_output( + MultiVersionStructV1::New(123, MakeRect(5))); MultiVersionStructV1Ptr output = SerializeAndDeserialize<MultiVersionStructV1Ptr>(std::move(input)); @@ -404,8 +348,7 @@ TEST_F(StructTest, Versioning_NewToOld) { { MultiVersionStructPtr input = MakeMultiVersionStruct(); - MultiVersionStructV0Ptr expected_output(MultiVersionStructV0::New()); - expected_output->f_int32 = 123; + MultiVersionStructV0Ptr expected_output(MultiVersionStructV0::New(123)); MultiVersionStructV0Ptr output = SerializeAndDeserialize<MultiVersionStructV0Ptr>(std::move(input)); @@ -420,65 +363,66 @@ TEST_F(StructTest, Serialization_NativeStruct) { { // Serialization of a null native struct. NativeStructPtr native; - size_t size = - mojo::internal::PrepareToSerialize<NativeStructPtr>(native, nullptr); + size_t size = mojo::internal::PrepareToSerialize<NativeStructDataView>( + native, nullptr); EXPECT_EQ(0u, size); mojo::internal::FixedBufferForTesting buf(size); Data* data = nullptr; - mojo::internal::Serialize<NativeStructPtr>(std::move(native), &buf, &data, - nullptr); + mojo::internal::Serialize<NativeStructDataView>(std::move(native), &buf, + &data, nullptr); EXPECT_EQ(nullptr, data); NativeStructPtr output_native; - mojo::internal::Deserialize<NativeStructPtr>(data, &output_native, nullptr); + mojo::internal::Deserialize<NativeStructDataView>(data, &output_native, + nullptr); EXPECT_TRUE(output_native.is_null()); } { // Serialization of a native struct with null data. NativeStructPtr native(NativeStruct::New()); - size_t size = - mojo::internal::PrepareToSerialize<NativeStructPtr>(native, nullptr); + size_t size = mojo::internal::PrepareToSerialize<NativeStructDataView>( + native, nullptr); EXPECT_EQ(0u, size); mojo::internal::FixedBufferForTesting buf(size); Data* data = nullptr; - mojo::internal::Serialize<NativeStructPtr>(std::move(native), &buf, &data, - nullptr); + mojo::internal::Serialize<NativeStructDataView>(std::move(native), &buf, + &data, nullptr); EXPECT_EQ(nullptr, data); NativeStructPtr output_native; - mojo::internal::Deserialize<NativeStructPtr>(data, &output_native, nullptr); + mojo::internal::Deserialize<NativeStructDataView>(data, &output_native, + nullptr); EXPECT_TRUE(output_native.is_null()); } { NativeStructPtr native(NativeStruct::New()); - native->data = Array<uint8_t>(2); - native->data[0] = 'X'; - native->data[1] = 'Y'; + native->data = std::vector<uint8_t>{'X', 'Y'}; - size_t size = - mojo::internal::PrepareToSerialize<NativeStructPtr>(native, nullptr); + size_t size = mojo::internal::PrepareToSerialize<NativeStructDataView>( + native, nullptr); EXPECT_EQ(16u, size); mojo::internal::FixedBufferForTesting buf(size); Data* data = nullptr; - mojo::internal::Serialize<NativeStructPtr>(std::move(native), &buf, &data, - nullptr); + mojo::internal::Serialize<NativeStructDataView>(std::move(native), &buf, + &data, nullptr); EXPECT_NE(nullptr, data); NativeStructPtr output_native; - mojo::internal::Deserialize<NativeStructPtr>(data, &output_native, nullptr); - EXPECT_FALSE(output_native.is_null()); - EXPECT_FALSE(output_native->data.is_null()); - EXPECT_EQ(2u, output_native->data.size()); - EXPECT_EQ('X', output_native->data[0]); - EXPECT_EQ('Y', output_native->data[1]); + mojo::internal::Deserialize<NativeStructDataView>(data, &output_native, + nullptr); + ASSERT_TRUE(output_native); + ASSERT_FALSE(output_native->data->empty()); + EXPECT_EQ(2u, output_native->data->size()); + EXPECT_EQ('X', (*output_native->data)[0]); + EXPECT_EQ('Y', (*output_native->data)[1]); } } @@ -486,7 +430,7 @@ TEST_F(StructTest, Serialization_PublicAPI) { { // A null struct pointer. RectPtr null_struct; - mojo::Array<uint8_t> data = Rect::Serialize(&null_struct); + auto data = Rect::Serialize(&null_struct); EXPECT_TRUE(data.empty()); // Initialize it to non-null. @@ -498,7 +442,7 @@ TEST_F(StructTest, Serialization_PublicAPI) { { // A struct with no fields. EmptyStructPtr empty_struct(EmptyStruct::New()); - mojo::Array<uint8_t> data = EmptyStruct::Serialize(&empty_struct); + auto data = EmptyStruct::Serialize(&empty_struct); EXPECT_FALSE(data.empty()); EmptyStructPtr output; @@ -510,7 +454,7 @@ TEST_F(StructTest, Serialization_PublicAPI) { // A simple struct. RectPtr rect = MakeRect(); RectPtr cloned_rect = rect.Clone(); - mojo::Array<uint8_t> data = Rect::Serialize(&rect); + auto data = Rect::Serialize(&rect); RectPtr output; ASSERT_TRUE(Rect::Deserialize(std::move(data), &output)); @@ -519,17 +463,17 @@ TEST_F(StructTest, Serialization_PublicAPI) { { // A struct containing other objects. - NamedRegionPtr region(NamedRegion::New()); - region->name.emplace("region"); - region->rects.emplace(3); - for (size_t i = 0; i < region->rects->size(); ++i) - (*region->rects)[i] = MakeRect(static_cast<int32_t>(i) + 1); + std::vector<RectPtr> rects; + for (size_t i = 0; i < 3; ++i) + rects.push_back(MakeRect(static_cast<int32_t>(i) + 1)); + NamedRegionPtr region( + NamedRegion::New(std::string("region"), std::move(rects))); NamedRegionPtr cloned_region = region.Clone(); - mojo::Array<uint8_t> data = NamedRegion::Serialize(®ion); + auto data = NamedRegion::Serialize(®ion); // Make sure that the serialized result gets pointers encoded properly. - mojo::Array<uint8_t> cloned_data = data.Clone(); + auto cloned_data = data; NamedRegionPtr output; ASSERT_TRUE(NamedRegion::Deserialize(std::move(cloned_data), &output)); EXPECT_TRUE(output.Equals(cloned_region)); @@ -538,12 +482,34 @@ TEST_F(StructTest, Serialization_PublicAPI) { { // Deserialization failure. RectPtr rect = MakeRect(); - mojo::Array<uint8_t> data = Rect::Serialize(&rect); + auto data = Rect::Serialize(&rect); NamedRegionPtr output; EXPECT_FALSE(NamedRegion::Deserialize(std::move(data), &output)); } } +TEST_F(StructTest, VersionedStructConstructor) { + auto reordered = ReorderedStruct::New(123, 456, 789); + EXPECT_EQ(123, reordered->a); + EXPECT_EQ(456, reordered->b); + EXPECT_EQ(789, reordered->c); + + reordered = ReorderedStruct::New(123, 456); + EXPECT_EQ(123, reordered->a); + EXPECT_EQ(6, reordered->b); + EXPECT_EQ(456, reordered->c); + + reordered = ReorderedStruct::New(123); + EXPECT_EQ(3, reordered->a); + EXPECT_EQ(6, reordered->b); + EXPECT_EQ(123, reordered->c); + + reordered = ReorderedStruct::New(); + EXPECT_EQ(3, reordered->a); + EXPECT_EQ(6, reordered->b); + EXPECT_EQ(1, reordered->c); +} + } // namespace test } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits.typemap b/mojo/public/cpp/bindings/tests/struct_with_traits.typemap index da061de..752ce44 100644 --- a/mojo/public/cpp/bindings/tests/struct_with_traits.typemap +++ b/mojo/public/cpp/bindings/tests/struct_with_traits.typemap @@ -19,6 +19,8 @@ type_mappings = [ "mojo.test.EnumWithTraits=mojo::test::EnumWithTraitsImpl", "mojo.test.StructWithTraits=mojo::test::StructWithTraitsImpl", "mojo.test.NestedStructWithTraits=mojo::test::NestedStructWithTraitsImpl", - "mojo.test.PassByValueStructWithTraits=mojo::test::PassByValueStructWithTraitsImpl[move_only]", - "mojo.test.StructWithTraitsForUniquePtrTest=std::unique_ptr<int>[move_only]", + "mojo.test.TrivialStructWithTraits=mojo::test::TrivialStructWithTraitsImpl[copyable_pass_by_value]", + "mojo.test.MoveOnlyStructWithTraits=mojo::test::MoveOnlyStructWithTraitsImpl[move_only]", + "mojo.test.StructWithTraitsForUniquePtr=std::unique_ptr<int>[move_only,nullable_is_same_type]", + "mojo.test.UnionWithTraits=std::unique_ptr<mojo::test::UnionWithTraitsBase>[move_only,nullable_is_same_type]", ] diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl.cc b/mojo/public/cpp/bindings/tests/struct_with_traits_impl.cc index e99ec2a..cbdd4bf 100644 --- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl.cc +++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl.cc @@ -18,12 +18,19 @@ StructWithTraitsImpl::~StructWithTraitsImpl() {} StructWithTraitsImpl::StructWithTraitsImpl(const StructWithTraitsImpl& other) = default; -PassByValueStructWithTraitsImpl::PassByValueStructWithTraitsImpl() {} +MoveOnlyStructWithTraitsImpl::MoveOnlyStructWithTraitsImpl() {} -PassByValueStructWithTraitsImpl::PassByValueStructWithTraitsImpl( - PassByValueStructWithTraitsImpl&& other) = default; +MoveOnlyStructWithTraitsImpl::MoveOnlyStructWithTraitsImpl( + MoveOnlyStructWithTraitsImpl&& other) = default; -PassByValueStructWithTraitsImpl::~PassByValueStructWithTraitsImpl() {} +MoveOnlyStructWithTraitsImpl::~MoveOnlyStructWithTraitsImpl() {} + +MoveOnlyStructWithTraitsImpl& MoveOnlyStructWithTraitsImpl::operator=( + MoveOnlyStructWithTraitsImpl&& other) = default; + +UnionWithTraitsInt32::~UnionWithTraitsInt32() {} + +UnionWithTraitsStruct::~UnionWithTraitsStruct() {} } // namespace test } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl.h b/mojo/public/cpp/bindings/tests/struct_with_traits_impl.h index b62ba56..7b007cc 100644 --- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl.h +++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl.h @@ -8,6 +8,7 @@ #include <stdint.h> #include <map> +#include <set> #include <string> #include <vector> @@ -61,6 +62,11 @@ class StructWithTraitsImpl { } std::vector<std::string>& get_mutable_string_array() { return string_array_; } + const std::set<std::string>& get_string_set() const { + return string_set_; + } + std::set<std::string>& get_mutable_string_set() { return string_set_; } + const NestedStructWithTraitsImpl& get_struct() const { return struct_; } NestedStructWithTraitsImpl& get_mutable_struct() { return struct_; } @@ -86,24 +92,74 @@ class StructWithTraitsImpl { uint64_t uint64_ = 0; std::string string_; std::vector<std::string> string_array_; + std::set<std::string> string_set_; NestedStructWithTraitsImpl struct_; std::vector<NestedStructWithTraitsImpl> struct_array_; std::map<std::string, NestedStructWithTraitsImpl> struct_map_; }; -// A type which knows how to look like a mojo::test::PassByValueStructWithTraits +// A type which knows how to look like a mojo::test::TrivialStructWithTraits +// mojom type by way of mojo::StructTraits. +struct TrivialStructWithTraitsImpl { + int32_t value; +}; + +// A type which knows how to look like a mojo::test::MoveOnlyStructWithTraits // mojom type by way of mojo::StructTraits. -class PassByValueStructWithTraitsImpl { +class MoveOnlyStructWithTraitsImpl { public: - PassByValueStructWithTraitsImpl(); - PassByValueStructWithTraitsImpl(PassByValueStructWithTraitsImpl&& other); - ~PassByValueStructWithTraitsImpl(); + MoveOnlyStructWithTraitsImpl(); + MoveOnlyStructWithTraitsImpl(MoveOnlyStructWithTraitsImpl&& other); + ~MoveOnlyStructWithTraitsImpl(); ScopedHandle& get_mutable_handle() { return handle_; } + MoveOnlyStructWithTraitsImpl& operator=(MoveOnlyStructWithTraitsImpl&& other); + private: ScopedHandle handle_; - DISALLOW_COPY_AND_ASSIGN(PassByValueStructWithTraitsImpl); + DISALLOW_COPY_AND_ASSIGN(MoveOnlyStructWithTraitsImpl); +}; + +class UnionWithTraitsBase { + public: + enum class Type { INT32, STRUCT }; + + virtual ~UnionWithTraitsBase() {} + + Type type() const { return type_; } + + protected: + Type type_ = Type::INT32; +}; + +class UnionWithTraitsInt32 : public UnionWithTraitsBase { + public: + UnionWithTraitsInt32() {} + explicit UnionWithTraitsInt32(int32_t value) : value_(value) {} + + ~UnionWithTraitsInt32() override; + + int32_t value() const { return value_; } + void set_value(int32_t value) { value_ = value; } + + private: + int32_t value_ = 0; +}; + +class UnionWithTraitsStruct : public UnionWithTraitsBase { + public: + UnionWithTraitsStruct() { type_ = Type::STRUCT; } + explicit UnionWithTraitsStruct(int32_t value) : struct_(value) { + type_ = Type::STRUCT; + } + ~UnionWithTraitsStruct() override; + + NestedStructWithTraitsImpl& get_mutable_struct() { return struct_; } + const NestedStructWithTraitsImpl& get_struct() const { return struct_; } + + private: + NestedStructWithTraitsImpl struct_; }; } // namespace test diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc index c11b37a..6b770b1 100644 --- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc +++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc @@ -14,7 +14,7 @@ struct Context { } // namespace // static -void* StructTraits<test::NestedStructWithTraits, +void* StructTraits<test::NestedStructWithTraitsDataView, test::NestedStructWithTraitsImpl>:: SetUpContext(const test::NestedStructWithTraitsImpl& input) { Context* context = new Context; @@ -23,7 +23,7 @@ void* StructTraits<test::NestedStructWithTraits, } // static -void StructTraits<test::NestedStructWithTraits, +void StructTraits<test::NestedStructWithTraitsDataView, test::NestedStructWithTraitsImpl>:: TearDownContext(const test::NestedStructWithTraitsImpl& input, void* context) { @@ -33,7 +33,7 @@ void StructTraits<test::NestedStructWithTraits, } // static -int32_t StructTraits<test::NestedStructWithTraits, +int32_t StructTraits<test::NestedStructWithTraitsDataView, test::NestedStructWithTraitsImpl>:: value(const test::NestedStructWithTraitsImpl& input, void* context) { Context* context_obj = static_cast<Context*>(context); @@ -42,7 +42,7 @@ int32_t StructTraits<test::NestedStructWithTraits, } // static -bool StructTraits<test::NestedStructWithTraits, +bool StructTraits<test::NestedStructWithTraitsDataView, test::NestedStructWithTraitsImpl>:: Read(test::NestedStructWithTraits::DataView data, test::NestedStructWithTraitsImpl* output) { @@ -80,9 +80,9 @@ bool EnumTraits<test::EnumWithTraits, test::EnumWithTraitsImpl>::FromMojom( } // static -bool StructTraits<test::StructWithTraits, test::StructWithTraitsImpl>::Read( - test::StructWithTraits::DataView data, - test::StructWithTraitsImpl* out) { +bool StructTraits<test::StructWithTraitsDataView, test::StructWithTraitsImpl>:: + Read(test::StructWithTraits::DataView data, + test::StructWithTraitsImpl* out) { test::EnumWithTraitsImpl f_enum; if (!data.ReadFEnum(&f_enum)) return false; @@ -103,6 +103,16 @@ bool StructTraits<test::StructWithTraits, test::StructWithTraitsImpl>::Read( if (!data.ReadFStringArray(&out->get_mutable_string_array())) return false; + // We can't deserialize as a std::set, so we have to manually copy from the + // data view. + ArrayDataView<StringDataView> string_set_data_view; + data.GetFStringSetDataView(&string_set_data_view); + for (size_t i = 0; i < string_set_data_view.size(); ++i) { + std::string value; + string_set_data_view.Read(i, &value); + out->get_mutable_string_set().insert(value); + } + if (!data.ReadFStruct(&out->get_mutable_struct())) return false; @@ -116,10 +126,10 @@ bool StructTraits<test::StructWithTraits, test::StructWithTraitsImpl>::Read( } // static -bool StructTraits<test::PassByValueStructWithTraits, - test::PassByValueStructWithTraitsImpl>:: - Read(test::PassByValueStructWithTraits::DataView data, - test::PassByValueStructWithTraitsImpl* out) { +bool StructTraits<test::MoveOnlyStructWithTraitsDataView, + test::MoveOnlyStructWithTraitsImpl>:: + Read(test::MoveOnlyStructWithTraits::DataView data, + test::MoveOnlyStructWithTraitsImpl* out) { out->get_mutable_handle() = data.TakeFHandle(); return true; } diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h index 4550526..adcad8a 100644 --- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h +++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h @@ -18,7 +18,7 @@ namespace mojo { template <> -struct StructTraits<test::NestedStructWithTraits, +struct StructTraits<test::NestedStructWithTraitsDataView, test::NestedStructWithTraitsImpl> { static void* SetUpContext(const test::NestedStructWithTraitsImpl& input); static void TearDownContext(const test::NestedStructWithTraitsImpl& input, @@ -27,7 +27,7 @@ struct StructTraits<test::NestedStructWithTraits, static int32_t value(const test::NestedStructWithTraitsImpl& input, void* context); - static bool Read(test::NestedStructWithTraits::DataView data, + static bool Read(test::NestedStructWithTraitsDataView data, test::NestedStructWithTraitsImpl* output); }; @@ -39,9 +39,10 @@ struct EnumTraits<test::EnumWithTraits, test::EnumWithTraitsImpl> { }; template <> -struct StructTraits<test::StructWithTraits, test::StructWithTraitsImpl> { +struct StructTraits<test::StructWithTraitsDataView, + test::StructWithTraitsImpl> { // Deserialization to test::StructTraitsImpl. - static bool Read(test::StructWithTraits::DataView data, + static bool Read(test::StructWithTraitsDataView data, test::StructWithTraitsImpl* out); // Fields in test::StructWithTraits. @@ -76,6 +77,11 @@ struct StructTraits<test::StructWithTraits, test::StructWithTraitsImpl> { return value.get_string_array(); } + static const std::set<std::string>& f_string_set( + const test::StructWithTraitsImpl& value) { + return value.get_string_set(); + } + static const test::NestedStructWithTraitsImpl& f_struct( const test::StructWithTraitsImpl& value) { return value.get_struct(); @@ -93,31 +99,98 @@ struct StructTraits<test::StructWithTraits, test::StructWithTraitsImpl> { }; template <> -struct StructTraits<test::PassByValueStructWithTraits, - test::PassByValueStructWithTraitsImpl> { - // Deserialization to test::PassByValueStructTraitsImpl. - static bool Read(test::PassByValueStructWithTraits::DataView data, - test::PassByValueStructWithTraitsImpl* out); +struct StructTraits<test::TrivialStructWithTraitsDataView, + test::TrivialStructWithTraitsImpl> { + // Deserialization to test::TrivialStructTraitsImpl. + static bool Read(test::TrivialStructWithTraitsDataView data, + test::TrivialStructWithTraitsImpl* out) { + out->value = data.value(); + return true; + } + + // Fields in test::TrivialStructWithTraits. + // See src/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom. + static int32_t value(test::TrivialStructWithTraitsImpl& input) { + return input.value; + } +}; + +template <> +struct StructTraits<test::MoveOnlyStructWithTraitsDataView, + test::MoveOnlyStructWithTraitsImpl> { + // Deserialization to test::MoveOnlyStructTraitsImpl. + static bool Read(test::MoveOnlyStructWithTraitsDataView data, + test::MoveOnlyStructWithTraitsImpl* out); - // Fields in test::PassByValueStructWithTraits. + // Fields in test::MoveOnlyStructWithTraits. // See src/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom. - static ScopedHandle f_handle(test::PassByValueStructWithTraitsImpl& value) { + static ScopedHandle f_handle(test::MoveOnlyStructWithTraitsImpl& value) { return std::move(value.get_mutable_handle()); } }; template <> -struct StructTraits<test::StructWithTraitsForUniquePtrTest, +struct StructTraits<test::StructWithTraitsForUniquePtrDataView, std::unique_ptr<int>> { + static bool IsNull(const std::unique_ptr<int>& data) { return !data; } + static void SetToNull(std::unique_ptr<int>* data) { data->reset(); } + static int f_int32(const std::unique_ptr<int>& data) { return *data; } - static bool Read(test::StructWithTraitsForUniquePtrTest::DataView data, + static bool Read(test::StructWithTraitsForUniquePtrDataView data, std::unique_ptr<int>* out) { out->reset(new int(data.f_int32())); return true; } }; +template <> +struct UnionTraits<test::UnionWithTraitsDataView, + std::unique_ptr<test::UnionWithTraitsBase>> { + static bool IsNull(const std::unique_ptr<test::UnionWithTraitsBase>& data) { + return !data; + } + static void SetToNull(std::unique_ptr<test::UnionWithTraitsBase>* data) { + data->reset(); + } + + static test::UnionWithTraitsDataView::Tag GetTag( + const std::unique_ptr<test::UnionWithTraitsBase>& data) { + if (data->type() == test::UnionWithTraitsBase::Type::INT32) + return test::UnionWithTraitsDataView::Tag::F_INT32; + + return test::UnionWithTraitsDataView::Tag::F_STRUCT; + } + + static int32_t f_int32( + const std::unique_ptr<test::UnionWithTraitsBase>& data) { + return static_cast<test::UnionWithTraitsInt32*>(data.get())->value(); + } + + static const test::NestedStructWithTraitsImpl& f_struct( + const std::unique_ptr<test::UnionWithTraitsBase>& data) { + return static_cast<test::UnionWithTraitsStruct*>(data.get())->get_struct(); + } + + static bool Read(test::UnionWithTraitsDataView data, + std::unique_ptr<test::UnionWithTraitsBase>* out) { + switch (data.tag()) { + case test::UnionWithTraitsDataView::Tag::F_INT32: { + out->reset(new test::UnionWithTraitsInt32(data.f_int32())); + return true; + } + case test::UnionWithTraitsDataView::Tag::F_STRUCT: { + auto* struct_object = new test::UnionWithTraitsStruct(); + out->reset(struct_object); + return data.ReadFStruct(&struct_object->get_mutable_struct()); + } + } + + NOTREACHED(); + return false; + } +}; + } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_TESTS_STRUCT_WITH_TRAITS_IMPL_TRAITS_H_ diff --git a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc index 1253930..d0e5f10 100644 --- a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc +++ b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc @@ -267,13 +267,10 @@ class SyncMethodAssociatedTest : public SyncMethodTest { protected: void SetUp() override { - master_impl_.reset(new TestSyncMasterImpl(GetProxy(&master_ptr_))); + master_impl_.reset(new TestSyncMasterImpl(MakeRequest(&master_ptr_))); - master_ptr_.associated_group()->CreateAssociatedInterface( - AssociatedGroup::WILL_PASS_REQUEST, &asso_ptr_info_, &asso_request_); - master_ptr_.associated_group()->CreateAssociatedInterface( - AssociatedGroup::WILL_PASS_PTR, &opposite_asso_ptr_info_, - &opposite_asso_request_); + asso_request_ = MakeRequest(&asso_ptr_info_); + opposite_asso_request_ = MakeRequest(&opposite_asso_ptr_info_); master_impl_->set_send_interface_handler( [this](TestSyncAssociatedPtrInfo ptr) { @@ -335,14 +332,14 @@ TestSync::AsyncEchoCallback BindAsyncEchoCallback(Func func) { return base::Bind(&CallAsyncEchoCallback<Func>, func); } -// TestSync and TestSyncMaster exercise Router and MultiplexRouter, -// respectively. +// TestSync (without associated interfaces) and TestSyncMaster (with associated +// interfaces) exercise MultiplexRouter with different configurations. using InterfaceTypes = testing::Types<TestSync, TestSyncMaster>; TYPED_TEST_CASE(SyncMethodCommonTest, InterfaceTypes); TYPED_TEST(SyncMethodCommonTest, CallSyncMethodAsynchronously) { InterfacePtr<TypeParam> ptr; - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); base::RunLoop run_loop; ptr->Echo(123, base::Bind(&ExpectValueAndRunClosure, 123, @@ -357,7 +354,7 @@ TYPED_TEST(SyncMethodCommonTest, BasicSyncCalls) { service_thread.thread()->task_runner()->PostTask( FROM_HERE, base::Bind(&TestSyncServiceThread<TypeParam>::SetUp, base::Unretained(&service_thread), - base::Passed(GetProxy(&ptr)))); + base::Passed(MakeRequest(&ptr)))); ASSERT_TRUE(ptr->Ping()); ASSERT_TRUE(service_thread.ping_called()); @@ -379,7 +376,7 @@ TYPED_TEST(SyncMethodCommonTest, ReenteredBySyncMethodBinding) { InterfacePtr<TypeParam> ptr; // The binding lives on the same thread as the interface pointer. - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); int32_t output_value = -1; ASSERT_TRUE(ptr->Echo(42, &output_value)); EXPECT_EQ(42, output_value); @@ -390,7 +387,7 @@ TYPED_TEST(SyncMethodCommonTest, InterfacePtrDestroyedDuringSyncCall) { // destroyed while it is waiting for a sync call response. InterfacePtr<TypeParam> ptr; - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); impl.set_ping_handler([&ptr](const TestSync::PingCallback& callback) { ptr.reset(); callback.Run(); @@ -404,7 +401,7 @@ TYPED_TEST(SyncMethodCommonTest, BindingDestroyedDuringSyncCall) { // corresponding interface pointer is waiting for a sync call response. InterfacePtr<TypeParam> ptr; - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); impl.set_ping_handler([&impl](const TestSync::PingCallback& callback) { impl.binding()->Close(); callback.Run(); @@ -417,7 +414,7 @@ TYPED_TEST(SyncMethodCommonTest, NestedSyncCallsWithInOrderResponses) { // already a sync call ongoing. The responses arrive in order. InterfacePtr<TypeParam> ptr; - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); // The same variable is used to store the output of the two sync calls, in // order to test that responses are handled in the correct order. @@ -443,7 +440,7 @@ TYPED_TEST(SyncMethodCommonTest, NestedSyncCallsWithOutOfOrderResponses) { // already a sync call ongoing. The responses arrive out of order. InterfacePtr<TypeParam> ptr; - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); // The same variable is used to store the output of the two sync calls, in // order to test that responses are handled in the correct order. @@ -469,7 +466,7 @@ TYPED_TEST(SyncMethodCommonTest, AsyncResponseQueuedDuringSyncCall) { // call, async responses are queued until the sync call completes. InterfacePtr<TypeParam> ptr; - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); int32_t async_echo_request_value = -1; TestSync::AsyncEchoCallback async_echo_request_callback; @@ -525,7 +522,7 @@ TYPED_TEST(SyncMethodCommonTest, AsyncRequestQueuedDuringSyncCall) { // until the sync call completes. InterfacePtr<TypeParam> ptr; - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); bool async_echo_request_dispatched = false; impl.set_async_echo_handler([&async_echo_request_dispatched]( @@ -576,7 +573,7 @@ TYPED_TEST(SyncMethodCommonTest, // notification is delayed until all the queued messages are processed. InterfacePtr<TypeParam> ptr; - typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr)); + typename ImplTraits<TypeParam>::Type impl(MakeRequest(&ptr)); int32_t async_echo_request_value = -1; TestSync::AsyncEchoCallback async_echo_request_callback; diff --git a/mojo/public/cpp/bindings/tests/test_native_types_blink.typemap b/mojo/public/cpp/bindings/tests/test_native_types_blink.typemap index 258acd5..1bdfbbc 100644 --- a/mojo/public/cpp/bindings/tests/test_native_types_blink.typemap +++ b/mojo/public/cpp/bindings/tests/test_native_types_blink.typemap @@ -13,5 +13,5 @@ deps = [ type_mappings = [ "mojo.test.PickledEnum=mojo::test::PickledEnumBlink", - "mojo.test.PickledStruct=mojo::test::PickledStructBlink" + "mojo.test.PickledStruct=mojo::test::PickledStructBlink[move_only]", ] diff --git a/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap b/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap index a4c0f5a..50e8076 100644 --- a/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap +++ b/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap @@ -3,8 +3,7 @@ # found in the LICENSE file. mojom = "//mojo/public/interfaces/bindings/tests/test_native_types.mojom" -public_headers = - [ "//mojo/public/cpp/bindings/tests/pickled_types_chromium.h" ] +public_headers = [ "//mojo/public/cpp/bindings/tests/pickled_types_chromium.h" ] sources = [ "//mojo/public/cpp/bindings/tests/pickled_types_chromium.cc", ] @@ -14,5 +13,5 @@ deps = [ type_mappings = [ "mojo.test.PickledEnum=mojo::test::PickledEnumChromium", - "mojo.test.PickledStruct=mojo::test::PickledStructChromium" + "mojo.test.PickledStruct=mojo::test::PickledStructChromium[move_only]", ] diff --git a/mojo/public/cpp/bindings/tests/type_conversion_unittest.cc b/mojo/public/cpp/bindings/tests/type_conversion_unittest.cc index 7eb24ea..b0124aa 100644 --- a/mojo/public/cpp/bindings/tests/type_conversion_unittest.cc +++ b/mojo/public/cpp/bindings/tests/type_conversion_unittest.cc @@ -23,8 +23,8 @@ struct RedmondNamedRegion { std::vector<RedmondRect> rects; }; -bool AreEqualRectArrays(const Array<test::RectPtr>& rects1, - const Array<test::RectPtr>& rects2) { +bool AreEqualRectArrays(const std::vector<test::RectPtr>& rects1, + const std::vector<test::RectPtr>& rects2) { if (rects1.size() != rects2.size()) return false; @@ -44,12 +44,8 @@ bool AreEqualRectArrays(const Array<test::RectPtr>& rects1, template <> struct TypeConverter<test::RectPtr, RedmondRect> { static test::RectPtr Convert(const RedmondRect& input) { - test::RectPtr rect(test::Rect::New()); - rect->x = input.left; - rect->y = input.top; - rect->width = input.right - input.left; - rect->height = input.bottom - input.top; - return rect; + return test::Rect::New(input.left, input.top, input.right - input.left, + input.bottom - input.top); } }; @@ -68,10 +64,8 @@ struct TypeConverter<RedmondRect, test::RectPtr> { template <> struct TypeConverter<test::NamedRegionPtr, RedmondNamedRegion> { static test::NamedRegionPtr Convert(const RedmondNamedRegion& input) { - test::NamedRegionPtr region(test::NamedRegion::New()); - region->name.emplace(input.name); - region->rects = Array<test::RectPtr>::From(input.rects).PassStorage(); - return region; + return test::NamedRegion::New( + input.name, ConvertTo<std::vector<test::RectPtr>>(input.rects)); } }; @@ -93,53 +87,8 @@ struct TypeConverter<RedmondNamedRegion, test::NamedRegionPtr> { namespace test { namespace { -TEST(TypeConversionTest, String) { - const char kText[6] = "hello"; - - String a = std::string(kText); - String b(kText); - String c(static_cast<const char*>(kText)); - - EXPECT_EQ(std::string(kText), a.To<std::string>()); - EXPECT_EQ(std::string(kText), b.To<std::string>()); - EXPECT_EQ(std::string(kText), c.To<std::string>()); -} - -TEST(TypeConversionTest, String_Null) { - String a(nullptr); - EXPECT_TRUE(a.is_null()); - EXPECT_EQ(std::string(), a.To<std::string>()); - - String b = String::From(static_cast<const char*>(nullptr)); - EXPECT_TRUE(b.is_null()); -} - -TEST(TypeConversionTest, String_Empty) { - String a = ""; - EXPECT_EQ(std::string(), a.To<std::string>()); - - String b = std::string(); - EXPECT_FALSE(b.is_null()); - EXPECT_EQ(std::string(), b.To<std::string>()); -} - -TEST(TypeConversionTest, StringWithEmbeddedNull) { - const std::string kText("hel\0lo", 6); - - String a(kText); - EXPECT_EQ(kText, a.To<std::string>()); - - // Expect truncation: - String b(kText.c_str()); - EXPECT_EQ(std::string("hel"), b.To<std::string>()); -} - TEST(TypeConversionTest, CustomTypeConverter) { - RectPtr rect(Rect::New()); - rect->x = 10; - rect->y = 20; - rect->width = 50; - rect->height = 45; + RectPtr rect(Rect::New(10, 20, 50, 45)); RedmondRect rr = rect.To<RedmondRect>(); EXPECT_EQ(10, rr.left); @@ -155,9 +104,9 @@ TEST(TypeConversionTest, CustomTypeConverter) { } TEST(TypeConversionTest, CustomTypeConverter_Array_Null) { - Array<RectPtr> rects; + std::vector<RectPtr> rects; - std::vector<RedmondRect> redmond_rects = rects.To<std::vector<RedmondRect>>(); + auto redmond_rects = ConvertTo<std::vector<RedmondRect>>(rects); EXPECT_TRUE(redmond_rects.empty()); } @@ -165,7 +114,7 @@ TEST(TypeConversionTest, CustomTypeConverter_Array_Null) { TEST(TypeConversionTest, CustomTypeConverter_Array) { const RedmondRect kBase = {10, 20, 30, 40}; - Array<RectPtr> rects(10); + std::vector<RectPtr> rects(10); for (size_t i = 0; i < rects.size(); ++i) { RedmondRect rr = kBase; rr.left += static_cast<int32_t>(i); @@ -173,9 +122,9 @@ TEST(TypeConversionTest, CustomTypeConverter_Array) { rects[i] = Rect::From(rr); } - std::vector<RedmondRect> redmond_rects = rects.To<std::vector<RedmondRect>>(); + auto redmond_rects = ConvertTo<std::vector<RedmondRect>>(rects); - Array<RectPtr> rects2 = Array<RectPtr>::From(redmond_rects); + auto rects2 = ConvertTo<std::vector<RectPtr>>(redmond_rects); EXPECT_TRUE(AreEqualRectArrays(rects, rects2)); } diff --git a/mojo/public/cpp/bindings/tests/union_unittest.cc b/mojo/public/cpp/bindings/tests/union_unittest.cc index d65a348..bdf27df 100644 --- a/mojo/public/cpp/bindings/tests/union_unittest.cc +++ b/mojo/public/cpp/bindings/tests/union_unittest.cc @@ -9,14 +9,12 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "mojo/public/cpp/bindings/array.h" #include "mojo/public/cpp/bindings/binding.h" #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/lib/validation_context.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" -#include "mojo/public/cpp/bindings/string.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h" #include "mojo/public/interfaces/bindings/tests/test_unions.mojom.h" @@ -123,16 +121,17 @@ TEST(UnionTest, PodSerialization) { pod1->set_f_int8(10); mojo::internal::SerializationContext context; - size_t size = - mojo::internal::PrepareToSerialize<PodUnionPtr>(pod1, false, &context); + size_t size = mojo::internal::PrepareToSerialize<PodUnionDataView>( + pod1, false, &context); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = nullptr; - mojo::internal::Serialize<PodUnionPtr>(pod1, &buf, &data, false, &context); + mojo::internal::Serialize<PodUnionDataView>(pod1, &buf, &data, false, + &context); PodUnionPtr pod2; - mojo::internal::Deserialize<PodUnionPtr>(data, &pod2, &context); + mojo::internal::Deserialize<PodUnionDataView>(data, &pod2, &context); EXPECT_EQ(10, pod2->get_f_int8()); EXPECT_TRUE(pod2->is_f_int8()); @@ -143,16 +142,17 @@ TEST(UnionTest, EnumSerialization) { PodUnionPtr pod1(PodUnion::New()); pod1->set_f_enum(AnEnum::SECOND); - size_t size = - mojo::internal::PrepareToSerialize<PodUnionPtr>(pod1, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<PodUnionDataView>( + pod1, false, nullptr); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = nullptr; - mojo::internal::Serialize<PodUnionPtr>(pod1, &buf, &data, false, nullptr); + mojo::internal::Serialize<PodUnionDataView>(pod1, &buf, &data, false, + nullptr); PodUnionPtr pod2; - mojo::internal::Deserialize<PodUnionPtr>(data, &pod2, nullptr); + mojo::internal::Deserialize<PodUnionDataView>(data, &pod2, nullptr); EXPECT_EQ(AnEnum::SECOND, pod2->get_f_enum()); EXPECT_TRUE(pod2->is_f_enum()); @@ -164,16 +164,16 @@ TEST(UnionTest, PodValidation) { pod->set_f_int8(10); size_t size = - mojo::internal::PrepareToSerialize<PodUnionPtr>(pod, false, nullptr); + mojo::internal::PrepareToSerialize<PodUnionDataView>(pod, false, nullptr); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = nullptr; - mojo::internal::Serialize<PodUnionPtr>(pod, &buf, &data, false, nullptr); + mojo::internal::Serialize<PodUnionDataView>(pod, &buf, &data, false, nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE( internal::PodUnion_Data::Validate(raw_buf, &validation_context, false)); free(raw_buf); @@ -183,17 +183,17 @@ TEST(UnionTest, SerializeNotNull) { PodUnionPtr pod(PodUnion::New()); pod->set_f_int8(0); size_t size = - mojo::internal::PrepareToSerialize<PodUnionPtr>(pod, false, nullptr); + mojo::internal::PrepareToSerialize<PodUnionDataView>(pod, false, nullptr); mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = nullptr; - mojo::internal::Serialize<PodUnionPtr>(pod, &buf, &data, false, nullptr); + mojo::internal::Serialize<PodUnionDataView>(pod, &buf, &data, false, nullptr); EXPECT_FALSE(data->is_null()); } TEST(UnionTest, SerializeIsNullInlined) { PodUnionPtr pod; size_t size = - mojo::internal::PrepareToSerialize<PodUnionPtr>(pod, false, nullptr); + mojo::internal::PrepareToSerialize<PodUnionDataView>(pod, false, nullptr); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = internal::PodUnion_Data::New(&buf); @@ -203,28 +203,28 @@ TEST(UnionTest, SerializeIsNullInlined) { data->tag = PodUnion::Tag::F_UINT16; data->data.f_f_int16 = 20; - mojo::internal::Serialize<PodUnionPtr>(pod, &buf, &data, true, nullptr); + mojo::internal::Serialize<PodUnionDataView>(pod, &buf, &data, true, nullptr); EXPECT_TRUE(data->is_null()); PodUnionPtr pod2; - mojo::internal::Deserialize<PodUnionPtr>(data, &pod2, nullptr); + mojo::internal::Deserialize<PodUnionDataView>(data, &pod2, nullptr); EXPECT_TRUE(pod2.is_null()); } TEST(UnionTest, SerializeIsNullNotInlined) { PodUnionPtr pod; size_t size = - mojo::internal::PrepareToSerialize<PodUnionPtr>(pod, false, nullptr); + mojo::internal::PrepareToSerialize<PodUnionDataView>(pod, false, nullptr); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = nullptr; - mojo::internal::Serialize<PodUnionPtr>(pod, &buf, &data, false, nullptr); + mojo::internal::Serialize<PodUnionDataView>(pod, &buf, &data, false, nullptr); EXPECT_EQ(nullptr, data); } TEST(UnionTest, NullValidation) { void* buf = nullptr; - mojo::internal::ValidationContext validation_context(buf, 0, 0); + mojo::internal::ValidationContext validation_context(buf, 0, 0, 0); EXPECT_TRUE(internal::PodUnion_Data::Validate( buf, &validation_context, false)); } @@ -239,7 +239,7 @@ TEST(UnionTest, OutOfAlignmentValidation) { internal::PodUnion_Data* data = reinterpret_cast<internal::PodUnion_Data*>(buf); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_FALSE(internal::PodUnion_Data::Validate( buf, &validation_context, false)); free(raw_buf); @@ -250,7 +250,7 @@ TEST(UnionTest, OOBValidation) { mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = internal::PodUnion_Data::New(&buf); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); void* raw_buf = buf.Leak(); EXPECT_FALSE( internal::PodUnion_Data::Validate(raw_buf, &validation_context, false)); @@ -263,7 +263,7 @@ TEST(UnionTest, UnknownTagValidation) { internal::PodUnion_Data* data = internal::PodUnion_Data::New(&buf); data->tag = static_cast<internal::PodUnion_Data::PodUnion_Tag>(0xFFFFFF); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); void* raw_buf = buf.Leak(); EXPECT_FALSE( internal::PodUnion_Data::Validate(raw_buf, &validation_context, false)); @@ -275,16 +275,16 @@ TEST(UnionTest, UnknownEnumValueValidation) { pod->set_f_enum(static_cast<AnEnum>(0xFFFF)); size_t size = - mojo::internal::PrepareToSerialize<PodUnionPtr>(pod, false, nullptr); + mojo::internal::PrepareToSerialize<PodUnionDataView>(pod, false, nullptr); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = nullptr; - mojo::internal::Serialize<PodUnionPtr>(pod, &buf, &data, false, nullptr); + mojo::internal::Serialize<PodUnionDataView>(pod, &buf, &data, false, nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_FALSE( internal::PodUnion_Data::Validate(raw_buf, &validation_context, false)); free(raw_buf); @@ -295,16 +295,16 @@ TEST(UnionTest, UnknownExtensibleEnumValueValidation) { pod->set_f_extensible_enum(static_cast<AnExtensibleEnum>(0xFFFF)); size_t size = - mojo::internal::PrepareToSerialize<PodUnionPtr>(pod, false, nullptr); + mojo::internal::PrepareToSerialize<PodUnionDataView>(pod, false, nullptr); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::PodUnion_Data* data = nullptr; - mojo::internal::Serialize<PodUnionPtr>(pod, &buf, &data, false, nullptr); + mojo::internal::Serialize<PodUnionDataView>(pod, &buf, &data, false, nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE( internal::PodUnion_Data::Validate(raw_buf, &validation_context, false)); free(raw_buf); @@ -313,7 +313,7 @@ TEST(UnionTest, UnknownExtensibleEnumValueValidation) { TEST(UnionTest, StringGetterSetter) { ObjectUnionPtr pod(ObjectUnion::New()); - String hello("hello world"); + std::string hello("hello world"); pod->set_f_string(hello); EXPECT_EQ(hello, pod->get_f_string()); EXPECT_TRUE(pod->is_f_string()); @@ -335,7 +335,7 @@ TEST(UnionTest, StringEquals) { TEST(UnionTest, StringClone) { ObjectUnionPtr pod(ObjectUnion::New()); - String hello("hello world"); + std::string hello("hello world"); pod->set_f_string(hello); ObjectUnionPtr pod_clone = pod.Clone(); EXPECT_EQ(hello, pod_clone->get_f_string()); @@ -346,17 +346,18 @@ TEST(UnionTest, StringClone) { TEST(UnionTest, StringSerialization) { ObjectUnionPtr pod1(ObjectUnion::New()); - String hello("hello world"); + std::string hello("hello world"); pod1->set_f_string(hello); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(pod1, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + pod1, false, nullptr); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(pod1, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(pod1, &buf, &data, false, + nullptr); ObjectUnionPtr pod2; - mojo::internal::Deserialize<ObjectUnionPtr>(data, &pod2, nullptr); + mojo::internal::Deserialize<ObjectUnionDataView>(data, &pod2, nullptr); EXPECT_EQ(hello, pod2->get_f_string()); EXPECT_TRUE(pod2->is_f_string()); EXPECT_EQ(pod2->which(), ObjectUnion::Tag::F_STRING); @@ -369,7 +370,7 @@ TEST(UnionTest, NullStringValidation) { data->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; data->data.unknown = 0x0; mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); void* raw_buf = buf.Leak(); EXPECT_FALSE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); @@ -383,7 +384,7 @@ TEST(UnionTest, StringPointerOverflowValidation) { data->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; data->data.unknown = 0xFFFFFFFFFFFFFFFF; mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); void* raw_buf = buf.Leak(); EXPECT_FALSE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); @@ -402,7 +403,7 @@ TEST(UnionTest, StringValidateOOB) { reinterpret_cast<mojo::internal::ArrayHeader*>(ptr + *ptr); array_header->num_bytes = 20; // This should go out of bounds. array_header->num_elements = 20; - mojo::internal::ValidationContext validation_context(data, 32, 0); + mojo::internal::ValidationContext validation_context(data, 32, 0, 0); void* raw_buf = buf.Leak(); EXPECT_FALSE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); @@ -425,7 +426,7 @@ TEST(UnionTest, PodUnionInArray) { } TEST(UnionTest, PodUnionInArraySerialization) { - Array<PodUnionPtr> array(2); + std::vector<PodUnionPtr> array(2); array[0] = PodUnion::New(); array[1] = PodUnion::New(); @@ -434,17 +435,19 @@ TEST(UnionTest, PodUnionInArraySerialization) { EXPECT_EQ(2U, array.size()); size_t size = - mojo::internal::PrepareToSerialize<Array<PodUnionPtr>>(array, nullptr); + mojo::internal::PrepareToSerialize<ArrayDataView<PodUnionDataView>>( + array, nullptr); EXPECT_EQ(40U, size); mojo::internal::FixedBufferForTesting buf(size); mojo::internal::Array_Data<internal::PodUnion_Data>* data; mojo::internal::ContainerValidateParams validate_params(0, false, nullptr); - mojo::internal::Serialize<Array<PodUnionPtr>>(array, &buf, &data, - &validate_params, nullptr); + mojo::internal::Serialize<ArrayDataView<PodUnionDataView>>( + array, &buf, &data, &validate_params, nullptr); - Array<PodUnionPtr> array2; - mojo::internal::Deserialize<Array<PodUnionPtr>>(data, &array2, nullptr); + std::vector<PodUnionPtr> array2; + mojo::internal::Deserialize<ArrayDataView<PodUnionDataView>>(data, &array2, + nullptr); EXPECT_EQ(2U, array2.size()); @@ -453,24 +456,26 @@ TEST(UnionTest, PodUnionInArraySerialization) { } TEST(UnionTest, PodUnionInArraySerializationWithNull) { - Array<PodUnionPtr> array(2); + std::vector<PodUnionPtr> array(2); array[0] = PodUnion::New(); array[0]->set_f_int8(10); EXPECT_EQ(2U, array.size()); size_t size = - mojo::internal::PrepareToSerialize<Array<PodUnionPtr>>(array, nullptr); + mojo::internal::PrepareToSerialize<ArrayDataView<PodUnionDataView>>( + array, nullptr); EXPECT_EQ(40U, size); mojo::internal::FixedBufferForTesting buf(size); mojo::internal::Array_Data<internal::PodUnion_Data>* data; mojo::internal::ContainerValidateParams validate_params(0, true, nullptr); - mojo::internal::Serialize<Array<PodUnionPtr>>(array, &buf, &data, - &validate_params, nullptr); + mojo::internal::Serialize<ArrayDataView<PodUnionDataView>>( + array, &buf, &data, &validate_params, nullptr); - Array<PodUnionPtr> array2; - mojo::internal::Deserialize<Array<PodUnionPtr>>(data, &array2, nullptr); + std::vector<PodUnionPtr> array2; + mojo::internal::Deserialize<ArrayDataView<PodUnionDataView>>(data, &array2, + nullptr); EXPECT_EQ(2U, array2.size()); @@ -479,7 +484,7 @@ TEST(UnionTest, PodUnionInArraySerializationWithNull) { } TEST(UnionTest, ObjectUnionInArraySerialization) { - Array<ObjectUnionPtr> array(2); + std::vector<ObjectUnionPtr> array(2); array[0] = ObjectUnion::New(); array[1] = ObjectUnion::New(); @@ -488,15 +493,16 @@ TEST(UnionTest, ObjectUnionInArraySerialization) { EXPECT_EQ(2U, array.size()); size_t size = - mojo::internal::PrepareToSerialize<Array<ObjectUnionPtr>>(array, nullptr); + mojo::internal::PrepareToSerialize<ArrayDataView<ObjectUnionDataView>>( + array, nullptr); EXPECT_EQ(72U, size); mojo::internal::FixedBufferForTesting buf(size); mojo::internal::Array_Data<internal::ObjectUnion_Data>* data; mojo::internal::ContainerValidateParams validate_params(0, false, nullptr); - mojo::internal::Serialize<Array<ObjectUnionPtr>>(array, &buf, &data, - &validate_params, nullptr); + mojo::internal::Serialize<ArrayDataView<ObjectUnionDataView>>( + array, &buf, &data, &validate_params, nullptr); std::vector<char> new_buf; new_buf.resize(size); @@ -509,17 +515,18 @@ TEST(UnionTest, ObjectUnionInArraySerialization) { reinterpret_cast<mojo::internal::Array_Data<internal::ObjectUnion_Data>*>( new_buf.data()); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); ASSERT_TRUE(mojo::internal::Array_Data<internal::ObjectUnion_Data>::Validate( data, &validation_context, &validate_params)); - Array<ObjectUnionPtr> array2; - mojo::internal::Deserialize<Array<ObjectUnionPtr>>(data, &array2, nullptr); + std::vector<ObjectUnionPtr> array2; + mojo::internal::Deserialize<ArrayDataView<ObjectUnionDataView>>(data, &array2, + nullptr); EXPECT_EQ(2U, array2.size()); - EXPECT_EQ(String("hello"), array2[0]->get_f_string()); - EXPECT_EQ(String("world"), array2[1]->get_f_string()); + EXPECT_EQ("hello", array2[0]->get_f_string()); + EXPECT_EQ("world", array2[1]->get_f_string()); } // TODO(azani): Move back in struct_unittest.cc when possible. @@ -540,16 +547,17 @@ TEST(UnionTest, Serialization_UnionOfPods) { small_struct->pod_union->set_f_int32(10); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<SmallStructPtr>(small_struct, - &context); + size_t size = mojo::internal::PrepareToSerialize<SmallStructDataView>( + small_struct, &context); mojo::internal::FixedBufferForTesting buf(size); internal::SmallStruct_Data* data = nullptr; - mojo::internal::Serialize<SmallStructPtr>(small_struct, &buf, &data, - &context); + mojo::internal::Serialize<SmallStructDataView>(small_struct, &buf, &data, + &context); SmallStructPtr deserialized; - mojo::internal::Deserialize<SmallStructPtr>(data, &deserialized, &context); + mojo::internal::Deserialize<SmallStructDataView>(data, &deserialized, + &context); EXPECT_EQ(10, deserialized->pod_union->get_f_int32()); } @@ -558,19 +566,20 @@ TEST(UnionTest, Serialization_UnionOfPods) { TEST(UnionTest, Serialization_UnionOfObjects) { SmallObjStructPtr obj_struct(SmallObjStruct::New()); obj_struct->obj_union = ObjectUnion::New(); - String hello("hello world"); + std::string hello("hello world"); obj_struct->obj_union->set_f_string(hello); - size_t size = mojo::internal::PrepareToSerialize<SmallObjStructPtr>( + size_t size = mojo::internal::PrepareToSerialize<SmallObjStructDataView>( obj_struct, nullptr); mojo::internal::FixedBufferForTesting buf(size); internal::SmallObjStruct_Data* data = nullptr; - mojo::internal::Serialize<SmallObjStructPtr>(obj_struct, &buf, &data, - nullptr); + mojo::internal::Serialize<SmallObjStructDataView>(obj_struct, &buf, &data, + nullptr); SmallObjStructPtr deserialized; - mojo::internal::Deserialize<SmallObjStructPtr>(data, &deserialized, nullptr); + mojo::internal::Deserialize<SmallObjStructDataView>(data, &deserialized, + nullptr); EXPECT_EQ(hello, deserialized->obj_union->get_f_string()); } @@ -582,18 +591,17 @@ TEST(UnionTest, Validation_UnionsInStruct) { small_struct->pod_union->set_f_int32(10); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<SmallStructPtr>(small_struct, - &context); + size_t size = mojo::internal::PrepareToSerialize<SmallStructDataView>( + small_struct, &context); mojo::internal::FixedBufferForTesting buf(size); internal::SmallStruct_Data* data = nullptr; - mojo::internal::Serialize<SmallStructPtr>(small_struct, &buf, &data, - &context); - + mojo::internal::Serialize<SmallStructDataView>(small_struct, &buf, &data, + &context); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE(internal::SmallStruct_Data::Validate( raw_buf, &validation_context)); free(raw_buf); @@ -606,18 +614,18 @@ TEST(UnionTest, Validation_PodUnionInStruct_Failure) { small_struct->pod_union->set_f_int32(10); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<SmallStructPtr>(small_struct, - &context); + size_t size = mojo::internal::PrepareToSerialize<SmallStructDataView>( + small_struct, &context); mojo::internal::FixedBufferForTesting buf(size); internal::SmallStruct_Data* data = nullptr; - mojo::internal::Serialize<SmallStructPtr>(small_struct, &buf, &data, - &context); + mojo::internal::Serialize<SmallStructDataView>(small_struct, &buf, &data, + &context); data->pod_union.tag = static_cast<internal::PodUnion_Data::PodUnion_Tag>(100); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_FALSE(internal::SmallStruct_Data::Validate( raw_buf, &validation_context)); free(raw_buf); @@ -629,7 +637,7 @@ TEST(UnionTest, Validation_NullUnion_Failure) { SmallStructNonNullableUnion::New()); size_t size = - mojo::internal::PrepareToSerialize<SmallStructNonNullableUnionPtr>( + mojo::internal::PrepareToSerialize<SmallStructNonNullableUnionDataView>( small_struct, nullptr); mojo::internal::FixedBufferForTesting buf(size); @@ -638,7 +646,7 @@ TEST(UnionTest, Validation_NullUnion_Failure) { void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_FALSE(internal::SmallStructNonNullableUnion_Data::Validate( raw_buf, &validation_context)); free(raw_buf); @@ -649,17 +657,17 @@ TEST(UnionTest, Validation_NullableUnion) { SmallStructPtr small_struct(SmallStruct::New()); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<SmallStructPtr>(small_struct, - &context); + size_t size = mojo::internal::PrepareToSerialize<SmallStructDataView>( + small_struct, &context); mojo::internal::FixedBufferForTesting buf(size); internal::SmallStruct_Data* data = nullptr; - mojo::internal::Serialize<SmallStructPtr>(small_struct, &buf, &data, - &context); + mojo::internal::Serialize<SmallStructDataView>(small_struct, &buf, &data, + &context); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE(internal::SmallStruct_Data::Validate( raw_buf, &validation_context)); free(raw_buf); @@ -681,57 +689,58 @@ TEST(UnionTest, PodUnionInMap) { } TEST(UnionTest, PodUnionInMapSerialization) { - Map<String, PodUnionPtr> map; - map.insert("one", PodUnion::New()); - map.insert("two", PodUnion::New()); + using MojomType = MapDataView<StringDataView, PodUnionDataView>; + + std::unordered_map<std::string, PodUnionPtr> map; + map.insert(std::make_pair("one", PodUnion::New())); + map.insert(std::make_pair("two", PodUnion::New())); map["one"]->set_f_int8(8); map["two"]->set_f_int16(16); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<Map<String, PodUnionPtr>>( - map, &context); + size_t size = mojo::internal::PrepareToSerialize<MojomType>(map, &context); EXPECT_EQ(120U, size); mojo::internal::FixedBufferForTesting buf(size); - typename mojo::internal::MojomTypeTraits<Map<String, PodUnionPtr>>::Data* - data; + + typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; mojo::internal::ContainerValidateParams validate_params( new mojo::internal::ContainerValidateParams(0, false, nullptr), new mojo::internal::ContainerValidateParams(0, false, nullptr)); - mojo::internal::Serialize<Map<String, PodUnionPtr>>( - map, &buf, &data, &validate_params, &context); + mojo::internal::Serialize<MojomType>(map, &buf, &data, &validate_params, + &context); - Map<String, PodUnionPtr> map2; - mojo::internal::Deserialize<Map<String, PodUnionPtr>>(data, &map2, &context); + std::unordered_map<std::string, PodUnionPtr> map2; + mojo::internal::Deserialize<MojomType>(data, &map2, &context); EXPECT_EQ(8, map2["one"]->get_f_int8()); EXPECT_EQ(16, map2["two"]->get_f_int16()); } TEST(UnionTest, PodUnionInMapSerializationWithNull) { - Map<String, PodUnionPtr> map; - map.insert("one", PodUnion::New()); - map.insert("two", nullptr); + using MojomType = MapDataView<StringDataView, PodUnionDataView>; + + std::unordered_map<std::string, PodUnionPtr> map; + map.insert(std::make_pair("one", PodUnion::New())); + map.insert(std::make_pair("two", nullptr)); map["one"]->set_f_int8(8); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<Map<String, PodUnionPtr>>( - map, &context); + size_t size = mojo::internal::PrepareToSerialize<MojomType>(map, &context); EXPECT_EQ(120U, size); mojo::internal::FixedBufferForTesting buf(size); - typename mojo::internal::MojomTypeTraits<Map<String, PodUnionPtr>>::Data* - data; + typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; mojo::internal::ContainerValidateParams validate_params( new mojo::internal::ContainerValidateParams(0, false, nullptr), new mojo::internal::ContainerValidateParams(0, true, nullptr)); - mojo::internal::Serialize<Map<String, PodUnionPtr>>( - map, &buf, &data, &validate_params, &context); + mojo::internal::Serialize<MojomType>(map, &buf, &data, &validate_params, + &context); - Map<String, PodUnionPtr> map2; - mojo::internal::Deserialize<Map<String, PodUnionPtr>>(data, &map2, &context); + std::unordered_map<std::string, PodUnionPtr> map2; + mojo::internal::Deserialize<MojomType>(data, &map2, &context); EXPECT_EQ(8, map2["one"]->get_f_int8()); EXPECT_TRUE(map2["two"].is_null()); @@ -754,16 +763,17 @@ TEST(UnionTest, StructInUnionSerialization) { ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_dummy(std::move(dummy)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); EXPECT_EQ(32U, size); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); ObjectUnionPtr obj2; - mojo::internal::Deserialize<ObjectUnionPtr>(data, &obj2, nullptr); + mojo::internal::Deserialize<ObjectUnionDataView>(data, &obj2, nullptr); EXPECT_EQ(8, obj2->get_f_dummy()->f_int8); } @@ -774,16 +784,17 @@ TEST(UnionTest, StructInUnionValidation) { ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_dummy(std::move(dummy)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); free(raw_buf); @@ -797,16 +808,17 @@ TEST(UnionTest, StructInUnionValidationNonNullable) { ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_dummy(std::move(dummy)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_FALSE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); free(raw_buf); @@ -818,23 +830,24 @@ TEST(UnionTest, StructInUnionValidationNullable) { ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_nullable(std::move(dummy)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); free(raw_buf); } TEST(UnionTest, ArrayInUnionGetterSetter) { - Array<int8_t> array(2); + std::vector<int8_t> array(2); array[0] = 8; array[1] = 9; @@ -846,45 +859,47 @@ TEST(UnionTest, ArrayInUnionGetterSetter) { } TEST(UnionTest, ArrayInUnionSerialization) { - Array<int8_t> array(2); + std::vector<int8_t> array(2); array[0] = 8; array[1] = 9; ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_array_int8(std::move(array)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); EXPECT_EQ(32U, size); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); ObjectUnionPtr obj2; - mojo::internal::Deserialize<ObjectUnionPtr>(data, &obj2, nullptr); + mojo::internal::Deserialize<ObjectUnionDataView>(data, &obj2, nullptr); EXPECT_EQ(8, obj2->get_f_array_int8()[0]); EXPECT_EQ(9, obj2->get_f_array_int8()[1]); } TEST(UnionTest, ArrayInUnionValidation) { - Array<int8_t> array(2); + std::vector<int8_t> array(2); array[0] = 8; array[1] = 9; ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_array_int8(std::move(array)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); @@ -912,16 +927,17 @@ TEST(UnionTest, MapInUnionSerialization) { obj->set_f_map_int8(std::move(map)); mojo::internal::SerializationContext context; - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, &context); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, &context); EXPECT_EQ(112U, size); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, &context); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + &context); ObjectUnionPtr obj2; - mojo::internal::Deserialize<ObjectUnionPtr>(data, &obj2, &context); + mojo::internal::Deserialize<ObjectUnionDataView>(data, &obj2, &context); EXPECT_EQ(1, obj2->get_f_map_int8()["one"]); EXPECT_EQ(2, obj2->get_f_map_int8()["two"]); @@ -936,17 +952,18 @@ TEST(UnionTest, MapInUnionValidation) { obj->set_f_map_int8(std::move(map)); mojo::internal::SerializationContext context; - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, &context); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, &context); EXPECT_EQ(112U, size); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, &context); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + &context); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); @@ -970,16 +987,17 @@ TEST(UnionTest, UnionInUnionSerialization) { ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_pod_union(std::move(pod)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); EXPECT_EQ(32U, size); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); ObjectUnionPtr obj2; - mojo::internal::Deserialize<ObjectUnionPtr>(data, &obj2, nullptr); + mojo::internal::Deserialize<ObjectUnionDataView>(data, &obj2, nullptr); EXPECT_EQ(10, obj2->get_f_pod_union()->get_f_int8()); } @@ -990,17 +1008,18 @@ TEST(UnionTest, UnionInUnionValidation) { ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_pod_union(std::move(pod)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); EXPECT_EQ(32U, size); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_TRUE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); free(raw_buf); @@ -1014,16 +1033,17 @@ TEST(UnionTest, UnionInUnionValidationNonNullable) { ObjectUnionPtr obj(ObjectUnion::New()); obj->set_f_pod_union(std::move(pod)); - size_t size = - mojo::internal::PrepareToSerialize<ObjectUnionPtr>(obj, false, nullptr); + size_t size = mojo::internal::PrepareToSerialize<ObjectUnionDataView>( + obj, false, nullptr); mojo::internal::FixedBufferForTesting buf(size); internal::ObjectUnion_Data* data = nullptr; - mojo::internal::Serialize<ObjectUnionPtr>(obj, &buf, &data, false, nullptr); + mojo::internal::Serialize<ObjectUnionDataView>(obj, &buf, &data, false, + nullptr); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 0); + data, static_cast<uint32_t>(size), 0, 0); EXPECT_FALSE(internal::ObjectUnion_Data::Validate( raw_buf, &validation_context, false)); free(raw_buf); @@ -1057,18 +1077,18 @@ TEST(UnionTest, HandleInUnionSerialization) { handle->set_f_message_pipe(std::move(pipe1)); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<HandleUnionPtr>( + size_t size = mojo::internal::PrepareToSerialize<HandleUnionDataView>( handle, false, &context); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::HandleUnion_Data* data = nullptr; - mojo::internal::Serialize<HandleUnionPtr>(handle, &buf, &data, false, - &context); + mojo::internal::Serialize<HandleUnionDataView>(handle, &buf, &data, false, + &context); EXPECT_EQ(1U, context.handles.size()); HandleUnionPtr handle2(HandleUnion::New()); - mojo::internal::Deserialize<HandleUnionPtr>(data, &handle2, &context); + mojo::internal::Deserialize<HandleUnionDataView>(data, &handle2, &context); std::string golden("hello world"); WriteTextMessage(pipe0.get(), golden); @@ -1089,18 +1109,18 @@ TEST(UnionTest, HandleInUnionValidation) { handle->set_f_message_pipe(std::move(pipe1)); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<HandleUnionPtr>( + size_t size = mojo::internal::PrepareToSerialize<HandleUnionDataView>( handle, false, &context); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::HandleUnion_Data* data = nullptr; - mojo::internal::Serialize<HandleUnionPtr>(handle, &buf, &data, false, - &context); + mojo::internal::Serialize<HandleUnionDataView>(handle, &buf, &data, false, + &context); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 1); + data, static_cast<uint32_t>(size), 1, 0); EXPECT_TRUE(internal::HandleUnion_Data::Validate( raw_buf, &validation_context, false)); free(raw_buf); @@ -1114,18 +1134,18 @@ TEST(UnionTest, HandleInUnionValidationNull) { handle->set_f_message_pipe(std::move(pipe)); mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<HandleUnionPtr>( + size_t size = mojo::internal::PrepareToSerialize<HandleUnionDataView>( handle, false, &context); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::HandleUnion_Data* data = nullptr; - mojo::internal::Serialize<HandleUnionPtr>(handle, &buf, &data, false, - &context); + mojo::internal::Serialize<HandleUnionDataView>(handle, &buf, &data, false, + &context); void* raw_buf = buf.Leak(); mojo::internal::ValidationContext validation_context( - data, static_cast<uint32_t>(size), 1); + data, static_cast<uint32_t>(size), 1, 0); EXPECT_FALSE(internal::HandleUnion_Data::Validate( raw_buf, &validation_context, false)); free(raw_buf); @@ -1156,7 +1176,7 @@ TEST(UnionTest, InterfaceInUnion) { base::RunLoop run_loop; SmallCacheImpl impl(run_loop.QuitClosure()); SmallCachePtr ptr; - Binding<SmallCache> bindings(&impl, GetProxy(&ptr)); + Binding<SmallCache> bindings(&impl, MakeRequest(&ptr)); HandleUnionPtr handle(HandleUnion::New()); handle->set_f_small_cache(std::move(ptr)); @@ -1171,23 +1191,23 @@ TEST(UnionTest, InterfaceInUnionSerialization) { base::RunLoop run_loop; SmallCacheImpl impl(run_loop.QuitClosure()); SmallCachePtr ptr; - Binding<SmallCache> bindings(&impl, GetProxy(&ptr)); + Binding<SmallCache> bindings(&impl, MakeRequest(&ptr)); mojo::internal::SerializationContext context; HandleUnionPtr handle(HandleUnion::New()); handle->set_f_small_cache(std::move(ptr)); - size_t size = mojo::internal::PrepareToSerialize<HandleUnionPtr>( + size_t size = mojo::internal::PrepareToSerialize<HandleUnionDataView>( handle, false, &context); EXPECT_EQ(16U, size); mojo::internal::FixedBufferForTesting buf(size); internal::HandleUnion_Data* data = nullptr; - mojo::internal::Serialize<HandleUnionPtr>(handle, &buf, &data, false, - &context); + mojo::internal::Serialize<HandleUnionDataView>(handle, &buf, &data, false, + &context); EXPECT_EQ(1U, context.handles.size()); HandleUnionPtr handle2(HandleUnion::New()); - mojo::internal::Deserialize<HandleUnionPtr>(data, &handle2, &context); + mojo::internal::Deserialize<HandleUnionDataView>(data, &handle2, &context); handle2->get_f_small_cache()->SetIntValue(10); run_loop.Run(); @@ -1213,7 +1233,7 @@ TEST(UnionTest, UnionInInterface) { base::MessageLoop message_loop; UnionInterfaceImpl impl; UnionInterfacePtr ptr; - Binding<UnionInterface> bindings(&impl, GetProxy(&ptr)); + Binding<UnionInterface> bindings(&impl, MakeRequest(&ptr)); PodUnionPtr pod(PodUnion::New()); pod->set_f_int16(16); diff --git a/mojo/public/cpp/bindings/tests/validation_context_unittest.cc b/mojo/public/cpp/bindings/tests/validation_context_unittest.cc index aceaf1c..9ce9d60 100644 --- a/mojo/public/cpp/bindings/tests/validation_context_unittest.cc +++ b/mojo/public/cpp/bindings/tests/validation_context_unittest.cc @@ -17,6 +17,8 @@ namespace test { namespace { using Handle_Data = mojo::internal::Handle_Data; +using AssociatedEndpointHandle_Data = + mojo::internal::AssociatedEndpointHandle_Data; const void* ToPtr(uintptr_t ptr) { return reinterpret_cast<const void*>(ptr); @@ -27,7 +29,7 @@ TEST(ValidationContextTest, ConstructorRangeOverflow) { { // Test memory range overflow. internal::ValidationContext context( - ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 5000, 0); + ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 5000, 0, 0); EXPECT_FALSE(context.IsValidRange( ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 1)); @@ -35,11 +37,14 @@ TEST(ValidationContextTest, ConstructorRangeOverflow) { ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 1)); } - if (sizeof(size_t) > sizeof(uint32_t)) { + if (sizeof(size_t) <= sizeof(uint32_t)) + return; + + { // Test handle index range overflow. size_t num_handles = static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 5; - internal::ValidationContext context(ToPtr(0), 0, num_handles); + internal::ValidationContext context(ToPtr(0), 0, num_handles, 0); EXPECT_FALSE(context.ClaimHandle(Handle_Data(0))); EXPECT_FALSE(context.ClaimHandle( @@ -48,12 +53,28 @@ TEST(ValidationContextTest, ConstructorRangeOverflow) { EXPECT_TRUE(context.ClaimHandle( Handle_Data(internal::kEncodedInvalidHandleValue))); } + + { + size_t num_associated_endpoint_handles = + static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 5; + internal::ValidationContext context(ToPtr(0), 0, 0, + num_associated_endpoint_handles); + + EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(0))); + EXPECT_FALSE( + context.ClaimAssociatedEndpointHandle(AssociatedEndpointHandle_Data( + std::numeric_limits<uint32_t>::max() - 1))); + + EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); + } } #endif TEST(ValidationContextTest, IsValidRange) { { - internal::ValidationContext context(ToPtr(1234), 100, 0); + internal::ValidationContext context(ToPtr(1234), 100, 0, 0); // Basics. EXPECT_FALSE(context.IsValidRange(ToPtr(100), 5)); @@ -79,7 +100,7 @@ TEST(ValidationContextTest, IsValidRange) { } { - internal::ValidationContext context(ToPtr(1234), 100, 0); + internal::ValidationContext context(ToPtr(1234), 100, 0, 0); // Should return false for empty ranges. EXPECT_FALSE(context.IsValidRange(ToPtr(0), 0)); EXPECT_FALSE(context.IsValidRange(ToPtr(1200), 0)); @@ -90,7 +111,7 @@ TEST(ValidationContextTest, IsValidRange) { { // The valid memory range is empty. - internal::ValidationContext context(ToPtr(1234), 0, 0); + internal::ValidationContext context(ToPtr(1234), 0, 0, 0); EXPECT_FALSE(context.IsValidRange(ToPtr(1234), 1)); EXPECT_FALSE(context.IsValidRange(ToPtr(1234), 0)); @@ -98,7 +119,7 @@ TEST(ValidationContextTest, IsValidRange) { { internal::ValidationContext context( - ToPtr(std::numeric_limits<uintptr_t>::max() - 2000), 1000, 0); + ToPtr(std::numeric_limits<uintptr_t>::max() - 2000), 1000, 0, 0); // Test overflow. EXPECT_FALSE(context.IsValidRange( @@ -115,7 +136,7 @@ TEST(ValidationContextTest, IsValidRange) { TEST(ValidationContextTest, ClaimHandle) { { - internal::ValidationContext context(ToPtr(0), 0, 10); + internal::ValidationContext context(ToPtr(0), 0, 10, 0); // Basics. EXPECT_TRUE(context.ClaimHandle(Handle_Data(0))); @@ -137,7 +158,7 @@ TEST(ValidationContextTest, ClaimHandle) { { // No handle to claim. - internal::ValidationContext context(ToPtr(0), 0, 0); + internal::ValidationContext context(ToPtr(0), 0, 0, 0); EXPECT_FALSE(context.ClaimHandle(Handle_Data(0))); @@ -152,7 +173,7 @@ TEST(ValidationContextTest, ClaimHandle) { EXPECT_EQ(internal::kEncodedInvalidHandleValue, std::numeric_limits<uint32_t>::max()); internal::ValidationContext context( - ToPtr(0), 0, std::numeric_limits<uint32_t>::max()); + ToPtr(0), 0, std::numeric_limits<uint32_t>::max(), 0); EXPECT_TRUE(context.ClaimHandle( Handle_Data(std::numeric_limits<uint32_t>::max() - 1))); @@ -166,9 +187,71 @@ TEST(ValidationContextTest, ClaimHandle) { } } +TEST(ValidationContextTest, ClaimAssociatedEndpointHandle) { + { + internal::ValidationContext context(ToPtr(0), 0, 0, 10); + + // Basics. + EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(0))); + EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(0))); + + EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(9))); + EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(10))); + + // Should fail because it is smaller than the max index that has been + // claimed. + EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(8))); + + // Should return true for invalid handle. + EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); + EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); + } + + { + // No handle to claim. + internal::ValidationContext context(ToPtr(0), 0, 0, 0); + + EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(0))); + + // Should still return true for invalid handle. + EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); + } + + { + // Test the case that |num_associated_endpoint_handles| is the same value as + // |internal::kEncodedInvalidHandleValue|. + EXPECT_EQ(internal::kEncodedInvalidHandleValue, + std::numeric_limits<uint32_t>::max()); + internal::ValidationContext context(ToPtr(0), 0, 0, + std::numeric_limits<uint32_t>::max()); + + EXPECT_TRUE( + context.ClaimAssociatedEndpointHandle(AssociatedEndpointHandle_Data( + std::numeric_limits<uint32_t>::max() - 1))); + EXPECT_FALSE( + context.ClaimAssociatedEndpointHandle(AssociatedEndpointHandle_Data( + std::numeric_limits<uint32_t>::max() - 1))); + EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(0))); + + // Should still return true for invalid handle. + EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( + AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); + } +} + TEST(ValidationContextTest, ClaimMemory) { { - internal::ValidationContext context(ToPtr(1000), 2000, 0); + internal::ValidationContext context(ToPtr(1000), 2000, 0, 0); // Basics. EXPECT_FALSE(context.ClaimMemory(ToPtr(500), 100)); @@ -186,7 +269,7 @@ TEST(ValidationContextTest, ClaimMemory) { { // No memory to claim. - internal::ValidationContext context(ToPtr(10000), 0, 0); + internal::ValidationContext context(ToPtr(10000), 0, 0, 0); EXPECT_FALSE(context.ClaimMemory(ToPtr(10000), 1)); EXPECT_FALSE(context.ClaimMemory(ToPtr(10000), 0)); @@ -194,7 +277,7 @@ TEST(ValidationContextTest, ClaimMemory) { { internal::ValidationContext context( - ToPtr(std::numeric_limits<uintptr_t>::max() - 1000), 500, 0); + ToPtr(std::numeric_limits<uintptr_t>::max() - 1000), 500, 0, 0); // Test overflow. EXPECT_FALSE(context.ClaimMemory( diff --git a/mojo/public/cpp/bindings/tests/validation_unittest.cc b/mojo/public/cpp/bindings/tests/validation_unittest.cc index d254383..7af7396 100644 --- a/mojo/public/cpp/bindings/tests/validation_unittest.cc +++ b/mojo/public/cpp/bindings/tests/validation_unittest.cc @@ -16,9 +16,8 @@ #include "mojo/public/c/system/macros.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/connector.h" +#include "mojo/public/cpp/bindings/filter_chain.h" #include "mojo/public/cpp/bindings/interface_ptr.h" -#include "mojo/public/cpp/bindings/lib/filter_chain.h" -#include "mojo/public/cpp/bindings/lib/router.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/bindings/message_header_validator.h" @@ -266,7 +265,7 @@ class IntegrationTestInterfaceImpl : public IntegrationTestInterface { void Method0(BasicStructPtr param0, const Method0Callback& callback) override { - callback.Run(Array<uint8_t>::New(0u)); + callback.Run(std::vector<uint8_t>()); } }; @@ -376,20 +375,20 @@ TEST_F(ValidationTest, InputParser) { TEST_F(ValidationTest, Conformance) { DummyMessageReceiver dummy_receiver; - mojo::internal::FilterChain validators(&dummy_receiver); + mojo::FilterChain validators(&dummy_receiver); validators.Append<mojo::MessageHeaderValidator>(); validators.Append<ConformanceTestInterface::RequestValidator_>(); - RunValidationTests("conformance_", validators.GetHead()); + RunValidationTests("conformance_", &validators); } TEST_F(ValidationTest, AssociatedConformace) { DummyMessageReceiver dummy_receiver; - mojo::internal::FilterChain validators(&dummy_receiver); + mojo::FilterChain validators(&dummy_receiver); validators.Append<mojo::MessageHeaderValidator>(); validators.Append<AssociatedConformanceTestInterface::RequestValidator_>(); - RunValidationTests("associated_conformance_", validators.GetHead()); + RunValidationTests("associated_conformance_", &validators); } // This test is similar to Conformance test but its goal is specifically @@ -397,31 +396,31 @@ TEST_F(ValidationTest, AssociatedConformace) { // detection of off-by-one errors in method ordinals. TEST_F(ValidationTest, BoundsCheck) { DummyMessageReceiver dummy_receiver; - mojo::internal::FilterChain validators(&dummy_receiver); + mojo::FilterChain validators(&dummy_receiver); validators.Append<mojo::MessageHeaderValidator>(); validators.Append<BoundsCheckTestInterface::RequestValidator_>(); - RunValidationTests("boundscheck_", validators.GetHead()); + RunValidationTests("boundscheck_", &validators); } // This test is similar to the Conformance test but for responses. TEST_F(ValidationTest, ResponseConformance) { DummyMessageReceiver dummy_receiver; - mojo::internal::FilterChain validators(&dummy_receiver); + mojo::FilterChain validators(&dummy_receiver); validators.Append<mojo::MessageHeaderValidator>(); validators.Append<ConformanceTestInterface::ResponseValidator_>(); - RunValidationTests("resp_conformance_", validators.GetHead()); + RunValidationTests("resp_conformance_", &validators); } // This test is similar to the BoundsCheck test but for responses. TEST_F(ValidationTest, ResponseBoundsCheck) { DummyMessageReceiver dummy_receiver; - mojo::internal::FilterChain validators(&dummy_receiver); + mojo::FilterChain validators(&dummy_receiver); validators.Append<mojo::MessageHeaderValidator>(); validators.Append<BoundsCheckTestInterface::ResponseValidator_>(); - RunValidationTests("resp_boundscheck_", validators.GetHead()); + RunValidationTests("resp_boundscheck_", &validators); } // Test that InterfacePtr<X> applies the correct validators and they don't diff --git a/mojo/public/cpp/bindings/tests/versioning_apptest.cc b/mojo/public/cpp/bindings/tests/versioning_apptest.cc index 3a08cdd..95a89c0 100644 --- a/mojo/public/cpp/bindings/tests/versioning_apptest.cc +++ b/mojo/public/cpp/bindings/tests/versioning_apptest.cc @@ -7,8 +7,8 @@ #include "base/macros.h" #include "mojo/public/interfaces/bindings/tests/versioning_test_client.mojom.h" -#include "services/shell/public/cpp/application_test_base.h" -#include "services/shell/public/cpp/connector.h" +#include "services/service_manager/public/cpp/application_test_base.h" +#include "services/service_manager/public/cpp/connector.h" namespace mojo { namespace test { @@ -24,7 +24,7 @@ class VersioningApplicationTest : public ApplicationTestBase { void SetUp() override { ApplicationTestBase::SetUp(); - connector()->ConnectToInterface("mojo:versioning_test_service", &database_); + connector()->BindInterface("versioning_test_service", &database_); } HumanResourceDatabasePtr database_; diff --git a/mojo/public/cpp/bindings/tests/versioning_test_service.cc b/mojo/public/cpp/bindings/tests/versioning_test_service.cc index 2f554d9..313a624 100644 --- a/mojo/public/cpp/bindings/tests/versioning_test_service.cc +++ b/mojo/public/cpp/bindings/tests/versioning_test_service.cc @@ -8,12 +8,12 @@ #include <utility> #include "base/macros.h" -#include "mojo/public/c/system/main.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/interfaces/bindings/tests/versioning_test_service.mojom.h" -#include "services/shell/public/cpp/application_runner.h" -#include "services/shell/public/cpp/interface_factory.h" -#include "services/shell/public/cpp/service.h" +#include "services/service_manager/public/c/main.h" +#include "services/service_manager/public/cpp/interface_factory.h" +#include "services/service_manager/public/cpp/service.h" +#include "services/service_manager/public/cpp/service_runner.h" namespace mojo { namespace test { @@ -95,12 +95,12 @@ class HumanResourceDatabaseImpl : public HumanResourceDatabase { }; class HumanResourceSystemServer - : public shell::Service, + : public service_manager::Service, public InterfaceFactory<HumanResourceDatabase> { public: HumanResourceSystemServer() {} - // shell::Service implementation. + // service_manager::Service implementation. bool OnConnect(Connection* connection) override { connection->AddInterface<HumanResourceDatabase>(this); return true; @@ -119,8 +119,8 @@ class HumanResourceSystemServer } // namespace test } // namespace mojo -MojoResult MojoMain(MojoHandle request) { - mojo::ApplicationRunner runner( +MojoResult ServiceMain(MojoHandle request) { + mojo::ServiceRunner runner( new mojo::test::versioning::HumanResourceSystemServer()); return runner.Run(request); diff --git a/mojo/public/cpp/bindings/tests/wtf_array_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_array_unittest.cc deleted file mode 100644 index bb54b9c..0000000 --- a/mojo/public/cpp/bindings/tests/wtf_array_unittest.cc +++ /dev/null @@ -1,62 +0,0 @@ -// 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 "mojo/public/cpp/bindings/wtf_array.h" - -#include "mojo/public/cpp/bindings/lib/serialization.h" -#include "mojo/public/cpp/bindings/lib/wtf_serialization.h" -#include "mojo/public/cpp/bindings/tests/array_common_test.h" -#include "mojo/public/cpp/bindings/tests/container_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace test { -namespace { - -using WTFArrayTest = testing::Test; - -ARRAY_COMMON_TEST(WTFArray, NullAndEmpty) -ARRAY_COMMON_TEST(WTFArray, Basic) -ARRAY_COMMON_TEST(WTFArray, Bool) -ARRAY_COMMON_TEST(WTFArray, Handle) -ARRAY_COMMON_TEST(WTFArray, HandlesAreClosed) -ARRAY_COMMON_TEST(WTFArray, Clone) -ARRAY_COMMON_TEST(WTFArray, Serialization_ArrayOfPOD) -ARRAY_COMMON_TEST(WTFArray, Serialization_EmptyArrayOfPOD) -ARRAY_COMMON_TEST(WTFArray, Serialization_ArrayOfArrayOfPOD) -ARRAY_COMMON_TEST(WTFArray, Serialization_ArrayOfBool) -ARRAY_COMMON_TEST(WTFArray, Serialization_ArrayOfString) -ARRAY_COMMON_TEST(WTFArray, Resize_Copyable) -ARRAY_COMMON_TEST(WTFArray, Resize_MoveOnly) - -TEST_F(WTFArrayTest, MoveFromAndToWTFVector_Copyable) { - WTF::Vector<CopyableType> vec1(1); - WTFArray<CopyableType> arr(std::move(vec1)); - ASSERT_EQ(1u, arr.size()); - ASSERT_FALSE(arr[0].copied()); - - WTF::Vector<CopyableType> vec2(arr.PassStorage()); - ASSERT_EQ(1u, vec2.size()); - ASSERT_FALSE(vec2[0].copied()); - - ASSERT_EQ(0u, arr.size()); - ASSERT_TRUE(arr.is_null()); -} - -TEST_F(WTFArrayTest, MoveFromAndToWTFVector_MoveOnly) { - WTF::Vector<MoveOnlyType> vec1(1); - WTFArray<MoveOnlyType> arr(std::move(vec1)); - - ASSERT_EQ(1u, arr.size()); - - WTF::Vector<MoveOnlyType> vec2(arr.PassStorage()); - ASSERT_EQ(1u, vec2.size()); - - ASSERT_EQ(0u, arr.size()); - ASSERT_TRUE(arr.is_null()); -} - -} // namespace -} // namespace test -} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/wtf_hash_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_hash_unittest.cc new file mode 100644 index 0000000..959d25b --- /dev/null +++ b/mojo/public/cpp/bindings/tests/wtf_hash_unittest.cc @@ -0,0 +1,60 @@ +// 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 "mojo/public/cpp/bindings/lib/wtf_hash_util.h" + +#include "mojo/public/interfaces/bindings/tests/test_structs.mojom-blink.h" +#include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom-blink.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/Source/wtf/HashFunctions.h" + +namespace mojo { +namespace test { +namespace { + +using WTFHashTest = testing::Test; + +TEST_F(WTFHashTest, NestedStruct) { + // Just check that this template instantiation compiles. + ASSERT_EQ(::mojo::internal::Hash( + ::mojo::internal::kHashSeed, + blink::SimpleNestedStruct::New(blink::ContainsOther::New(1))), + ::mojo::internal::Hash( + ::mojo::internal::kHashSeed, + blink::SimpleNestedStruct::New(blink::ContainsOther::New(1)))); +} + +TEST_F(WTFHashTest, UnmappedNativeStruct) { + // Just check that this template instantiation compiles. + ASSERT_EQ(::mojo::internal::Hash(::mojo::internal::kHashSeed, + blink::UnmappedNativeStruct::New()), + ::mojo::internal::Hash(::mojo::internal::kHashSeed, + blink::UnmappedNativeStruct::New())); +} + +TEST_F(WTFHashTest, Enum) { + // Just check that this template instantiation compiles. + + // Top-level. + ASSERT_EQ(WTF::DefaultHash<blink::TopLevelEnum>::Hash().hash( + blink::TopLevelEnum::E0), + WTF::DefaultHash<blink::TopLevelEnum>::Hash().hash( + blink::TopLevelEnum::E0)); + + // Nested in struct. + ASSERT_EQ(WTF::DefaultHash<blink::TestWTFStruct::NestedEnum>::Hash().hash( + blink::TestWTFStruct::NestedEnum::E0), + WTF::DefaultHash<blink::TestWTFStruct::NestedEnum>::Hash().hash( + blink::TestWTFStruct::NestedEnum::E0)); + + // Nested in interface. + ASSERT_EQ(WTF::DefaultHash<blink::TestWTF::NestedEnum>::Hash().hash( + blink::TestWTF::NestedEnum::E0), + WTF::DefaultHash<blink::TestWTF::NestedEnum>::Hash().hash( + blink::TestWTF::NestedEnum::E0)); +} + +} // namespace +} // namespace test +} // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/wtf_map_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_map_unittest.cc index a70c134..5028087 100644 --- a/mojo/public/cpp/bindings/tests/wtf_map_unittest.cc +++ b/mojo/public/cpp/bindings/tests/wtf_map_unittest.cc @@ -1,65 +1,39 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// Copyright 2017 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 "mojo/public/cpp/bindings/wtf_map.h" - -#include "mojo/public/cpp/bindings/lib/wtf_serialization.h" -#include "mojo/public/cpp/bindings/tests/container_test_util.h" -#include "mojo/public/cpp/bindings/tests/map_common_test.h" -#include "mojo/public/cpp/bindings/wtf_array.h" +#include "mojo/public/cpp/bindings/tests/rect_blink.h" +#include "mojo/public/interfaces/bindings/tests/rect.mojom-blink.h" +#include "mojo/public/interfaces/bindings/tests/test_structs.mojom-blink.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/Source/wtf/text/WTFString.h" namespace mojo { namespace test { - namespace { -using WTFMapTest = testing::Test; - -MAP_COMMON_TEST(WTFMap, NullAndEmpty) -MAP_COMMON_TEST(WTFMap, InsertWorks) -MAP_COMMON_TEST(WTFMap, TestIndexOperator) -MAP_COMMON_TEST(WTFMap, TestIndexOperatorAsRValue) -MAP_COMMON_TEST(WTFMap, TestIndexOperatorMoveOnly) -MAP_COMMON_TEST(WTFMap, MapArrayClone) -MAP_COMMON_TEST(WTFMap, ArrayOfMap) +TEST(WTFMapTest, StructKey) { + WTF::HashMap<blink::RectPtr, int32_t> map; + map.insert(blink::Rect::New(1, 2, 3, 4), 123); -TEST_F(WTFMapTest, MoveFromAndToWTFHashMap_Copyable) { - WTF::HashMap<int32_t, CopyableType> map1; - map1.add(123, CopyableType()); - map1.find(123)->value.ResetCopied(); - ASSERT_FALSE(map1.find(123)->value.copied()); + blink::RectPtr key = blink::Rect::New(1, 2, 3, 4); + ASSERT_NE(map.end(), map.find(key)); + ASSERT_EQ(123, map.find(key)->value); - WTFMap<int32_t, CopyableType> mojo_map(std::move(map1)); - ASSERT_EQ(1u, mojo_map.size()); - ASSERT_NE(mojo_map.end(), mojo_map.find(123)); - ASSERT_FALSE(mojo_map[123].copied()); - - WTF::HashMap<int32_t, CopyableType> map2(mojo_map.PassStorage()); - ASSERT_EQ(1u, map2.size()); - ASSERT_NE(map2.end(), map2.find(123)); - ASSERT_FALSE(map2.find(123)->value.copied()); - - ASSERT_EQ(0u, mojo_map.size()); - ASSERT_TRUE(mojo_map.is_null()); + map.remove(key); + ASSERT_EQ(0u, map.size()); } -TEST_F(WTFMapTest, MoveFromAndToWTFHashMap_MoveOnly) { - WTF::HashMap<int32_t, MoveOnlyType> map1; - map1.add(123, MoveOnlyType()); - - WTFMap<int32_t, MoveOnlyType> mojo_map(std::move(map1)); - ASSERT_EQ(1u, mojo_map.size()); - ASSERT_NE(mojo_map.end(), mojo_map.find(123)); +TEST(WTFMapTest, TypemappedStructKey) { + WTF::HashMap<blink::ContainsHashablePtr, int32_t> map; + map.insert(blink::ContainsHashable::New(RectBlink(1, 2, 3, 4)), 123); - WTF::HashMap<int32_t, MoveOnlyType> map2(mojo_map.PassStorage()); - ASSERT_EQ(1u, map2.size()); - ASSERT_NE(map2.end(), map2.find(123)); + blink::ContainsHashablePtr key = + blink::ContainsHashable::New(RectBlink(1, 2, 3, 4)); + ASSERT_NE(map.end(), map.find(key)); + ASSERT_EQ(123, map.find(key)->value); - ASSERT_EQ(0u, mojo_map.size()); - ASSERT_TRUE(mojo_map.is_null()); + map.remove(key); + ASSERT_EQ(0u, map.size()); } } // namespace diff --git a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc index 97392d4..363ef7c 100644 --- a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc +++ b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc @@ -14,6 +14,7 @@ #include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom-blink.h" #include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/Source/wtf/text/StringHash.h" namespace mojo { namespace test { @@ -75,9 +76,9 @@ WTF::Vector<WTF::String> ConstructStringArray() { WTF::HashMap<WTF::String, WTF::String> ConstructStringMap() { WTF::HashMap<WTF::String, WTF::String> str_map; // A null string as value. - str_map.add("0", WTF::String()); - str_map.add("1", kHelloWorld); - str_map.add("2", WTF::String::fromUTF8(kUTF8HelloWorld)); + str_map.insert("0", WTF::String()); + str_map.insert("1", kHelloWorld); + str_map.insert("2", WTF::String::fromUTF8(kUTF8HelloWorld)); return str_map; } @@ -106,140 +107,62 @@ void ExpectStringMap( } // namespace -TEST_F(WTFTypesTest, Serialization_WTFArrayToWTFArray) { - WTFArray<WTF::String> strs = ConstructStringArray(); - auto cloned_strs = strs.Clone(); - - mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<Array<mojo::String>>( - cloned_strs, &context); - - mojo::internal::FixedBufferForTesting buf(size); - typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data; - mojo::internal::ContainerValidateParams validate_params( - 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr)); - mojo::internal::Serialize<Array<mojo::String>>(cloned_strs, &buf, &data, - &validate_params, &context); - - WTFArray<WTF::String> strs2; - mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context); - - EXPECT_TRUE(strs.Equals(strs2)); -} - TEST_F(WTFTypesTest, Serialization_WTFVectorToWTFVector) { + using MojomType = ArrayDataView<StringDataView>; + WTF::Vector<WTF::String> strs = ConstructStringArray(); auto cloned_strs = strs; mojo::internal::SerializationContext context; - size_t size = mojo::internal::PrepareToSerialize<Array<mojo::String>>( - cloned_strs, &context); + size_t size = + mojo::internal::PrepareToSerialize<MojomType>(cloned_strs, &context); mojo::internal::FixedBufferForTesting buf(size); - typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data; + typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; mojo::internal::ContainerValidateParams validate_params( 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr)); - mojo::internal::Serialize<Array<mojo::String>>(cloned_strs, &buf, &data, - &validate_params, &context); + mojo::internal::Serialize<MojomType>(cloned_strs, &buf, &data, + &validate_params, &context); WTF::Vector<WTF::String> strs2; - mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context); + mojo::internal::Deserialize<MojomType>(data, &strs2, &context); EXPECT_EQ(strs, strs2); } -TEST_F(WTFTypesTest, Serialization_WTFArrayToMojoArray) { - WTFArray<WTF::String> strs = ConstructStringArray(); - - mojo::internal::SerializationContext context; - size_t size = - mojo::internal::PrepareToSerialize<Array<mojo::String>>(strs, &context); - - mojo::internal::FixedBufferForTesting buf(size); - typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data; - mojo::internal::ContainerValidateParams validate_params( - 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr)); - mojo::internal::Serialize<Array<mojo::String>>(strs, &buf, &data, - &validate_params, &context); - - Array<mojo::String> strs2; - mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context); - - ASSERT_EQ(4u, strs2.size()); - EXPECT_TRUE(strs2[0].is_null()); - EXPECT_TRUE("" == strs2[1]); - EXPECT_TRUE(kHelloWorld == strs2[2]); - EXPECT_TRUE(kUTF8HelloWorld == strs2[3]); -} - -TEST_F(WTFTypesTest, Serialization_WTFMapToWTFMap) { - using WTFType = WTFMap<WTF::String, WTF::String>; - using MojomType = Map<mojo::String, mojo::String>; +TEST_F(WTFTypesTest, Serialization_WTFVectorToStlVector) { + using MojomType = ArrayDataView<StringDataView>; - WTFType str_map = ConstructStringMap(); - WTFType cloned_str_map = str_map.Clone(); + WTF::Vector<WTF::String> strs = ConstructStringArray(); + auto cloned_strs = strs; mojo::internal::SerializationContext context; size_t size = - mojo::internal::PrepareToSerialize<MojomType>(cloned_str_map, &context); + mojo::internal::PrepareToSerialize<MojomType>(cloned_strs, &context); mojo::internal::FixedBufferForTesting buf(size); typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; mojo::internal::ContainerValidateParams validate_params( - new mojo::internal::ContainerValidateParams( - 0, false, - new mojo::internal::ContainerValidateParams(0, false, nullptr)), - new mojo::internal::ContainerValidateParams( - 0, true, - new mojo::internal::ContainerValidateParams(0, false, nullptr))); - mojo::internal::Serialize<MojomType>(cloned_str_map, &buf, &data, + 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr)); + mojo::internal::Serialize<MojomType>(cloned_strs, &buf, &data, &validate_params, &context); - WTFType str_map2; - mojo::internal::Deserialize<MojomType>(data, &str_map2, &context); - - EXPECT_TRUE(str_map.Equals(str_map2)); -} - -TEST_F(WTFTypesTest, Serialization_WTFMapToMojoMap) { - using WTFType = WTFMap<WTF::String, WTF::String>; - using MojomType = Map<mojo::String, mojo::String>; - - WTFType str_map = ConstructStringMap(); - - mojo::internal::SerializationContext context; - size_t size = - mojo::internal::PrepareToSerialize<MojomType>(str_map, &context); + std::vector<base::Optional<std::string>> strs2; + mojo::internal::Deserialize<MojomType>(data, &strs2, &context); - mojo::internal::FixedBufferForTesting buf(size); - typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; - mojo::internal::ContainerValidateParams validate_params( - new mojo::internal::ContainerValidateParams( - 0, false, - new mojo::internal::ContainerValidateParams(0, false, nullptr)), - new mojo::internal::ContainerValidateParams( - 0, true, - new mojo::internal::ContainerValidateParams(0, false, nullptr))); - mojo::internal::Serialize<MojomType>(str_map, &buf, &data, &validate_params, - &context); - - MojomType str_map2; - mojo::internal::Deserialize<MojomType>(data, &str_map2, &context); - - ASSERT_EQ(3u, str_map2.size()); - EXPECT_TRUE(str_map2["0"].is_null()); - EXPECT_TRUE(kHelloWorld == str_map2["1"]); - EXPECT_TRUE(kUTF8HelloWorld == str_map2["2"]); + ASSERT_EQ(4u, strs2.size()); + EXPECT_FALSE(strs2[0]); + EXPECT_EQ("", *strs2[1]); + EXPECT_EQ(kHelloWorld, *strs2[2]); + EXPECT_EQ(kUTF8HelloWorld, *strs2[3]); } TEST_F(WTFTypesTest, Serialization_PublicAPI) { - blink::TestWTFStructPtr input(blink::TestWTFStruct::New()); - input->str = kHelloWorld; - input->integer = 42; + blink::TestWTFStructPtr input(blink::TestWTFStruct::New(kHelloWorld, 42)); blink::TestWTFStructPtr cloned_input = input.Clone(); - WTFArray<uint8_t> data = blink::TestWTFStruct::Serialize(&input); + auto data = blink::TestWTFStruct::Serialize(&input); blink::TestWTFStructPtr output; ASSERT_TRUE(blink::TestWTFStruct::Deserialize(std::move(data), &output)); @@ -248,7 +171,7 @@ TEST_F(WTFTypesTest, Serialization_PublicAPI) { TEST_F(WTFTypesTest, SendString) { blink::TestWTFPtr ptr; - TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr))); + TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(MakeRequest(&ptr))); WTF::Vector<WTF::String> strs = ConstructStringArray(); @@ -267,7 +190,7 @@ TEST_F(WTFTypesTest, SendString) { TEST_F(WTFTypesTest, SendStringArray) { blink::TestWTFPtr ptr; - TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr))); + TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(MakeRequest(&ptr))); WTF::Optional<WTF::Vector<WTF::String>> arrs[3]; // arrs[0] is empty. @@ -293,7 +216,7 @@ TEST_F(WTFTypesTest, SendStringArray) { TEST_F(WTFTypesTest, SendStringMap) { blink::TestWTFPtr ptr; - TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr))); + TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(MakeRequest(&ptr))); WTF::Optional<WTF::HashMap<WTF::String, WTF::String>> maps[3]; // maps[0] is empty. diff --git a/mojo/public/cpp/bindings/unique_ptr_impl_ref_traits.h b/mojo/public/cpp/bindings/unique_ptr_impl_ref_traits.h new file mode 100644 index 0000000..f1ac097 --- /dev/null +++ b/mojo/public/cpp/bindings/unique_ptr_impl_ref_traits.h @@ -0,0 +1,22 @@ +// Copyright 2017 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_UNIQUE_PTR_IMPL_REF_TRAITS_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_UNIQUE_PTR_IMPL_REF_TRAITS_H_ + +namespace mojo { + +// Traits for a binding's implementation reference type. +// This corresponds to a unique_ptr reference type. +template <typename Interface> +struct UniquePtrImplRefTraits { + using PointerType = std::unique_ptr<Interface>; + + static bool IsNull(const PointerType& ptr) { return !ptr; } + static Interface* GetRawPointer(PointerType* ptr) { return ptr->get(); } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_UNIQUE_PTR_IMPL_REF_TRAITS_H_ |