| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <utility> |
| |
| #include "base/test/bind.h" |
| #include "base/test/task_environment.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "mojo/public/cpp/bindings/tests/nullable_value_types_enums.h" |
| #include "mojo/public/cpp/test_support/test_utils.h" |
| #include "mojo/public/interfaces/bindings/tests/nullable_value_types.mojom.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace mojo::test::nullable_value_types { |
| namespace { |
| |
| template <typename T> |
| inline constexpr T kDefaultValue = T(); |
| |
| template <> |
| inline constexpr mojom::RegularEnum kDefaultValue<mojom::RegularEnum> = |
| mojom::RegularEnum::kThisValue; |
| |
| template <> |
| inline constexpr TypemappedEnum kDefaultValue<TypemappedEnum> = |
| TypemappedEnum::kValueOne; |
| |
| template <typename T> |
| std::pair<bool, T> FromOpt(const absl::optional<T>& opt) { |
| return opt.has_value() ? std::pair(true, opt.value()) |
| : std::pair(false, kDefaultValue<T>); |
| } |
| |
| template <typename T> |
| absl::optional<T> ToOpt(bool has_value, T value) { |
| return has_value ? absl::make_optional(value) : absl::nullopt; |
| } |
| |
| absl::optional<mojom::RegularEnum> Transform( |
| absl::optional<mojom::RegularEnum> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| switch (in.value()) { |
| case mojom::RegularEnum::kThisValue: |
| return mojom::RegularEnum::kThatValue; |
| case mojom::RegularEnum::kThatValue: |
| return mojom::RegularEnum::kThisValue; |
| } |
| } |
| |
| absl::optional<TypemappedEnum> Transform(absl::optional<TypemappedEnum> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| switch (in.value()) { |
| case TypemappedEnum::kValueOne: |
| return TypemappedEnum::kValueTwo; |
| case TypemappedEnum::kValueTwo: |
| return TypemappedEnum::kValueOne; |
| } |
| } |
| |
| absl::optional<bool> Transform(absl::optional<bool> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return !in.value(); |
| } |
| |
| absl::optional<uint8_t> Transform(absl::optional<uint8_t> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return ~in.value(); |
| } |
| |
| absl::optional<uint16_t> Transform(absl::optional<uint16_t> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return ~in.value(); |
| } |
| |
| absl::optional<uint32_t> Transform(absl::optional<uint32_t> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return ~in.value(); |
| } |
| |
| absl::optional<uint64_t> Transform(absl::optional<uint64_t> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return ~in.value(); |
| } |
| |
| absl::optional<int8_t> Transform(absl::optional<int8_t> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return -in.value(); |
| } |
| |
| absl::optional<int16_t> Transform(absl::optional<int16_t> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return -in.value(); |
| } |
| |
| absl::optional<int32_t> Transform(absl::optional<int32_t> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return -in.value(); |
| } |
| |
| absl::optional<int64_t> Transform(absl::optional<int64_t> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return -in.value(); |
| } |
| |
| absl::optional<float> Transform(absl::optional<float> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return -2 * in.value(); |
| } |
| |
| absl::optional<double> Transform(absl::optional<double> in) { |
| if (!in.has_value()) { |
| return absl::nullopt; |
| } |
| return -2 * in.value(); |
| } |
| |
| class InterfaceV1Impl : public mojom::InterfaceV1 { |
| public: |
| explicit InterfaceV1Impl(PendingReceiver<mojom::InterfaceV1> receiver) |
| : receiver_(this, std::move(receiver)) {} |
| |
| private: |
| // mojom::InterfaceV1 implementation: |
| void MethodWithEnums(bool has_enum_value, |
| mojom::RegularEnum enum_value, |
| bool has_mapped_enum_value, |
| TypemappedEnum mapped_enum_value, |
| MethodWithEnumsCallback callback) override { |
| auto [out_has_enum_value, out_enum_value] = |
| FromOpt(Transform(ToOpt(has_enum_value, enum_value))); |
| auto [out_has_mapped_enum_value, out_mapped_enum_value] = |
| FromOpt(Transform(ToOpt(has_mapped_enum_value, mapped_enum_value))); |
| std::move(callback).Run(out_has_enum_value, out_enum_value, |
| out_has_mapped_enum_value, out_mapped_enum_value); |
| } |
| |
| void MethodWithStructWithEnums( |
| mojom::CompatibleStructWithEnumsPtr in, |
| MethodWithStructWithEnumsCallback callback) override { |
| auto [out_has_enum_value, out_enum_value] = |
| FromOpt(Transform(ToOpt(in->has_enum_value, in->enum_value))); |
| auto [out_has_mapped_enum_value, out_mapped_enum_value] = FromOpt( |
| Transform(ToOpt(in->has_mapped_enum_value, in->mapped_enum_value))); |
| std::move(callback).Run(mojom::CompatibleStructWithEnums::New( |
| out_has_enum_value, out_enum_value, out_has_mapped_enum_value, |
| out_mapped_enum_value)); |
| } |
| |
| void MethodWithNumerics(bool has_bool_value, |
| bool bool_value, |
| bool has_u8_value, |
| uint8_t u8_value, |
| bool has_u16_value, |
| uint16_t u16_value, |
| bool has_u32_value, |
| uint32_t u32_value, |
| bool has_u64_value, |
| uint64_t u64_value, |
| bool has_i8_value, |
| int8_t i8_value, |
| bool has_i16_value, |
| int16_t i16_value, |
| bool has_i32_value, |
| int32_t i32_value, |
| bool has_i64_value, |
| int64_t i64_value, |
| bool has_float_value, |
| float float_value, |
| bool has_double_value, |
| double double_value, |
| MethodWithNumericsCallback callback) override { |
| auto [out_has_bool_value, out_bool_value] = |
| FromOpt(Transform(ToOpt(has_bool_value, bool_value))); |
| auto [out_has_u8_value, out_u8_value] = |
| FromOpt(Transform(ToOpt(has_u8_value, u8_value))); |
| auto [out_has_u16_value, out_u16_value] = |
| FromOpt(Transform(ToOpt(has_u16_value, u16_value))); |
| auto [out_has_u32_value, out_u32_value] = |
| FromOpt(Transform(ToOpt(has_u32_value, u32_value))); |
| auto [out_has_u64_value, out_u64_value] = |
| FromOpt(Transform(ToOpt(has_u64_value, u64_value))); |
| auto [out_has_i8_value, out_i8_value] = |
| FromOpt(Transform(ToOpt(has_i8_value, i8_value))); |
| auto [out_has_i16_value, out_i16_value] = |
| FromOpt(Transform(ToOpt(has_i16_value, i16_value))); |
| auto [out_has_i32_value, out_i32_value] = |
| FromOpt(Transform(ToOpt(has_i32_value, i32_value))); |
| auto [out_has_i64_value, out_i64_value] = |
| FromOpt(Transform(ToOpt(has_i64_value, i64_value))); |
| auto [out_has_float_value, out_float_value] = |
| FromOpt(Transform(ToOpt(has_float_value, float_value))); |
| auto [out_has_double_value, out_double_value] = |
| FromOpt(Transform(ToOpt(has_double_value, double_value))); |
| std::move(callback).Run( |
| out_has_bool_value, out_bool_value, out_has_u8_value, out_u8_value, |
| out_has_u16_value, out_u16_value, out_has_u32_value, out_u32_value, |
| out_has_u64_value, out_u64_value, out_has_i8_value, out_i8_value, |
| out_has_i16_value, out_i16_value, out_has_i32_value, out_i32_value, |
| out_has_i64_value, out_i64_value, out_has_float_value, out_float_value, |
| out_has_double_value, out_double_value); |
| } |
| |
| void MethodWithStructWithNumerics( |
| mojom::CompatibleStructWithNumericsPtr in, |
| MethodWithStructWithNumericsCallback callback) override { |
| auto [out_has_bool_value, out_bool_value] = |
| FromOpt(Transform(ToOpt(in->has_bool_value, in->bool_value))); |
| auto [out_has_u8_value, out_u8_value] = |
| FromOpt(Transform(ToOpt(in->has_u8_value, in->u8_value))); |
| auto [out_has_u16_value, out_u16_value] = |
| FromOpt(Transform(ToOpt(in->has_u16_value, in->u16_value))); |
| auto [out_has_u32_value, out_u32_value] = |
| FromOpt(Transform(ToOpt(in->has_u32_value, in->u32_value))); |
| auto [out_has_u64_value, out_u64_value] = |
| FromOpt(Transform(ToOpt(in->has_u64_value, in->u64_value))); |
| auto [out_has_i8_value, out_i8_value] = |
| FromOpt(Transform(ToOpt(in->has_i8_value, in->i8_value))); |
| auto [out_has_i16_value, out_i16_value] = |
| FromOpt(Transform(ToOpt(in->has_i16_value, in->i16_value))); |
| auto [out_has_i32_value, out_i32_value] = |
| FromOpt(Transform(ToOpt(in->has_i32_value, in->i32_value))); |
| auto [out_has_i64_value, out_i64_value] = |
| FromOpt(Transform(ToOpt(in->has_i64_value, in->i64_value))); |
| auto [out_has_float_value, out_float_value] = |
| FromOpt(Transform(ToOpt(in->has_float_value, in->float_value))); |
| auto [out_has_double_value, out_double_value] = |
| FromOpt(Transform(ToOpt(in->has_double_value, in->double_value))); |
| std::move(callback).Run(mojom::CompatibleStructWithNumerics::New( |
| out_has_bool_value, out_bool_value, out_has_u8_value, out_u8_value, |
| out_has_u16_value, out_u16_value, out_has_u32_value, out_u32_value, |
| out_has_u64_value, out_u64_value, out_has_i8_value, out_i8_value, |
| out_has_i16_value, out_i16_value, out_has_i32_value, out_i32_value, |
| out_has_i64_value, out_i64_value, out_has_float_value, out_float_value, |
| out_has_double_value, out_double_value)); |
| } |
| |
| void MethodWithVersionedArgs( |
| MethodWithVersionedArgsCallback callback) override { |
| std::move(callback).Run(); |
| } |
| |
| void MethodWithVersionedStruct( |
| mojom::VersionedStructV1Ptr in, |
| MethodWithVersionedStructCallback callback) override { |
| std::move(callback).Run(std::move(in)); |
| } |
| |
| const Receiver<mojom::InterfaceV1> receiver_; |
| }; |
| |
| enum class CallerVersion { |
| kV1, |
| kV2, |
| }; |
| |
| class InterfaceV2Impl : public mojom::InterfaceV2 { |
| public: |
| explicit InterfaceV2Impl( |
| PendingReceiver<mojom::InterfaceV2> receiver, |
| absl::optional<CallerVersion> caller_version = absl::nullopt) |
| : receiver_(this, std::move(receiver)), caller_version_(caller_version) {} |
| |
| private: |
| // mojom::InterfaceV2 implementation: |
| void MethodWithEnums(absl::optional<mojom::RegularEnum> enum_value, |
| absl::optional<TypemappedEnum> mapped_enum_value, |
| MethodWithEnumsCallback callback) override { |
| std::move(callback).Run(Transform(enum_value), |
| Transform(mapped_enum_value)); |
| } |
| |
| void MethodWithStructWithEnums( |
| mojom::StructWithEnumsPtr in, |
| MethodWithStructWithEnumsCallback callback) override { |
| std::move(callback).Run(mojom::StructWithEnums::New( |
| Transform(in->enum_value), Transform(in->mapped_enum_value))); |
| } |
| |
| void MethodWithNumerics(absl::optional<bool> bool_value, |
| absl::optional<uint8_t> u8_value, |
| absl::optional<uint16_t> u16_value, |
| absl::optional<uint32_t> u32_value, |
| absl::optional<uint64_t> u64_value, |
| absl::optional<int8_t> i8_value, |
| absl::optional<int16_t> i16_value, |
| absl::optional<int32_t> i32_value, |
| absl::optional<int64_t> i64_value, |
| absl::optional<float> float_value, |
| absl::optional<double> double_value, |
| MethodWithNumericsCallback callback) override { |
| std::move(callback).Run( |
| Transform(bool_value), Transform(u8_value), Transform(u16_value), |
| Transform(u32_value), Transform(u64_value), Transform(i8_value), |
| Transform(i16_value), Transform(i32_value), Transform(i64_value), |
| Transform(float_value), Transform(double_value)); |
| } |
| |
| void MethodWithStructWithNumerics( |
| mojom::StructWithNumericsPtr in, |
| MethodWithStructWithNumericsCallback callback) override { |
| std::move(callback).Run(mojom::StructWithNumerics::New( |
| Transform(in->bool_value), Transform(in->u8_value), |
| Transform(in->u16_value), Transform(in->u32_value), |
| Transform(in->u64_value), Transform(in->i8_value), |
| Transform(in->i16_value), Transform(in->i32_value), |
| Transform(in->i64_value), Transform(in->float_value), |
| Transform(in->double_value))); |
| } |
| |
| void MethodWithVersionedArgs( |
| absl::optional<bool> bool_value, |
| absl::optional<uint8_t> u8_value, |
| absl::optional<uint16_t> u16_value, |
| absl::optional<uint32_t> u32_value, |
| absl::optional<uint64_t> u64_value, |
| absl::optional<int8_t> i8_value, |
| absl::optional<int16_t> i16_value, |
| absl::optional<int32_t> i32_value, |
| absl::optional<int64_t> i64_value, |
| absl::optional<float> float_value, |
| absl::optional<double> double_value, |
| absl::optional<mojom::RegularEnum> enum_value, |
| absl::optional<TypemappedEnum> mapped_enum_value, |
| MethodWithVersionedArgsCallback callback) override { |
| switch (*caller_version_) { |
| case CallerVersion::kV1: |
| // A caller using the V1 interface will not know about the new |
| // arguments, so they should all equal absl::nullopt. |
| EXPECT_EQ(absl::nullopt, bool_value); |
| EXPECT_EQ(absl::nullopt, u8_value); |
| EXPECT_EQ(absl::nullopt, u16_value); |
| EXPECT_EQ(absl::nullopt, u32_value); |
| EXPECT_EQ(absl::nullopt, u64_value); |
| EXPECT_EQ(absl::nullopt, i8_value); |
| EXPECT_EQ(absl::nullopt, i16_value); |
| EXPECT_EQ(absl::nullopt, i32_value); |
| EXPECT_EQ(absl::nullopt, i64_value); |
| EXPECT_EQ(absl::nullopt, float_value); |
| EXPECT_EQ(absl::nullopt, double_value); |
| EXPECT_EQ(absl::nullopt, enum_value); |
| EXPECT_EQ(absl::nullopt, mapped_enum_value); |
| break; |
| case CallerVersion::kV2: |
| EXPECT_EQ(true, bool_value); |
| EXPECT_EQ(uint8_t{1}, u8_value); |
| EXPECT_EQ(uint16_t{2}, u16_value); |
| EXPECT_EQ(uint32_t{4}, u32_value); |
| EXPECT_EQ(uint64_t{8}, u64_value); |
| EXPECT_EQ(int8_t{-16}, i8_value); |
| EXPECT_EQ(int16_t{-32}, i16_value); |
| EXPECT_EQ(int32_t{-64}, i32_value); |
| EXPECT_EQ(int64_t{-128}, i64_value); |
| EXPECT_EQ(256.0f, float_value); |
| EXPECT_EQ(-512.0, double_value); |
| EXPECT_EQ(mojom::RegularEnum::kThisValue, enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueTwo, mapped_enum_value); |
| break; |
| } |
| std::move(callback).Run( |
| false, uint8_t{128}, uint16_t{64}, uint32_t{32}, uint64_t{16}, |
| int8_t{-8}, int16_t{-4}, int32_t{-2}, int64_t{-1}, -0.5f, 0.25, |
| mojom::RegularEnum::kThatValue, TypemappedEnum::kValueOne); |
| } |
| |
| void MethodWithVersionedStruct( |
| mojom::VersionedStructV2Ptr in, |
| MethodWithVersionedStructCallback callback) override { |
| switch (*caller_version_) { |
| case CallerVersion::kV1: |
| // A caller using the V1 interface will not know about the new |
| // arguments, so they should all equal absl::nullopt. |
| EXPECT_EQ(absl::nullopt, in->bool_value); |
| EXPECT_EQ(absl::nullopt, in->u8_value); |
| EXPECT_EQ(absl::nullopt, in->u16_value); |
| EXPECT_EQ(absl::nullopt, in->u32_value); |
| EXPECT_EQ(absl::nullopt, in->u64_value); |
| EXPECT_EQ(absl::nullopt, in->i8_value); |
| EXPECT_EQ(absl::nullopt, in->i16_value); |
| EXPECT_EQ(absl::nullopt, in->i32_value); |
| EXPECT_EQ(absl::nullopt, in->i64_value); |
| EXPECT_EQ(absl::nullopt, in->float_value); |
| EXPECT_EQ(absl::nullopt, in->double_value); |
| EXPECT_EQ(absl::nullopt, in->enum_value); |
| EXPECT_EQ(absl::nullopt, in->mapped_enum_value); |
| break; |
| case CallerVersion::kV2: |
| EXPECT_EQ(true, in->bool_value); |
| EXPECT_EQ(uint8_t{1}, in->u8_value); |
| EXPECT_EQ(uint16_t{2}, in->u16_value); |
| EXPECT_EQ(uint32_t{4}, in->u32_value); |
| EXPECT_EQ(uint64_t{8}, in->u64_value); |
| EXPECT_EQ(int8_t{-16}, in->i8_value); |
| EXPECT_EQ(int16_t{-32}, in->i16_value); |
| EXPECT_EQ(int32_t{-64}, in->i32_value); |
| EXPECT_EQ(int64_t{-128}, in->i64_value); |
| EXPECT_EQ(256.0f, in->float_value); |
| EXPECT_EQ(-512.0, in->double_value); |
| EXPECT_EQ(mojom::RegularEnum::kThisValue, in->enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueTwo, in->mapped_enum_value); |
| break; |
| } |
| std::move(callback).Run(mojom::VersionedStructV2::New( |
| false, uint8_t{128}, uint16_t{64}, uint32_t{32}, uint64_t{16}, |
| int8_t{-8}, int16_t{-4}, int32_t{-2}, int64_t{-1}, -0.5f, 0.25, |
| mojom::RegularEnum::kThatValue, TypemappedEnum::kValueOne)); |
| } |
| |
| const Receiver<mojom::InterfaceV2> receiver_; |
| const absl::optional<CallerVersion> caller_version_; |
| }; |
| |
| class NullableValueTypes : public ::testing::Test { |
| base::test::SingleThreadTaskEnvironment task_environment; |
| }; |
| |
| TEST_F(NullableValueTypes, StructWithEnums) { |
| { |
| auto input = mojom::StructWithEnums::New(); |
| input->enum_value = absl::nullopt; |
| input->mapped_enum_value = absl::nullopt; |
| |
| mojom::StructWithEnumsPtr output; |
| ASSERT_TRUE(SerializeAndDeserialize<mojom::StructWithEnums>(input, output)); |
| |
| EXPECT_EQ(absl::nullopt, output->enum_value); |
| EXPECT_EQ(absl::nullopt, output->mapped_enum_value); |
| } |
| |
| { |
| auto input = mojom::StructWithEnums::New(); |
| input->enum_value = mojom::RegularEnum::kThisValue; |
| input->mapped_enum_value = absl::nullopt; |
| |
| mojom::StructWithEnumsPtr output; |
| ASSERT_TRUE(SerializeAndDeserialize<mojom::StructWithEnums>(input, output)); |
| |
| EXPECT_EQ(mojom::RegularEnum::kThisValue, output->enum_value); |
| EXPECT_EQ(absl::nullopt, output->mapped_enum_value); |
| } |
| |
| { |
| auto input = mojom::StructWithEnums::New(); |
| input->enum_value = absl::nullopt; |
| input->mapped_enum_value = TypemappedEnum::kValueOne; |
| |
| mojom::StructWithEnumsPtr output; |
| ASSERT_TRUE(SerializeAndDeserialize<mojom::StructWithEnums>(input, output)); |
| |
| EXPECT_EQ(absl::nullopt, output->enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueOne, output->mapped_enum_value); |
| } |
| |
| { |
| auto input = mojom::StructWithEnums::New(); |
| input->enum_value = mojom::RegularEnum::kThatValue; |
| input->mapped_enum_value = TypemappedEnum::kValueTwo; |
| |
| mojom::StructWithEnumsPtr output; |
| ASSERT_TRUE(SerializeAndDeserialize<mojom::StructWithEnums>(input, output)); |
| |
| EXPECT_EQ(mojom::RegularEnum::kThatValue, output->enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueTwo, output->mapped_enum_value); |
| } |
| } |
| |
| TEST_F(NullableValueTypes, MethodEnumArgsCompatibility) { |
| // Legacy bool+enum calling a receiver using optional<enum> |
| { |
| mojo::Remote<mojom::InterfaceV1> remote; |
| mojo::PendingReceiver<mojom::InterfaceV2> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV2Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithEnums( |
| false, /* ignored */ mojom::RegularEnum::kThisValue, false, |
| /* ignored */ TypemappedEnum::kValueOne, |
| base::BindLambdaForTesting([&](bool has_enum_value, |
| mojom::RegularEnum enum_value, |
| bool has_mapped_enum_value, |
| TypemappedEnum mapped_enum_value) { |
| EXPECT_FALSE(has_enum_value); |
| EXPECT_FALSE(has_mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithEnums( |
| true, mojom::RegularEnum::kThisValue, false, |
| /* ignored */ TypemappedEnum::kValueOne, |
| base::BindLambdaForTesting([&](bool has_enum_value, |
| mojom::RegularEnum enum_value, |
| bool has_mapped_enum_value, |
| TypemappedEnum mapped_enum_value) { |
| EXPECT_TRUE(has_enum_value); |
| EXPECT_EQ(mojom::RegularEnum::kThatValue, enum_value); |
| EXPECT_FALSE(has_mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithEnums( |
| false, /* ignored */ mojom::RegularEnum::kThisValue, true, |
| TypemappedEnum::kValueOne, |
| base::BindLambdaForTesting([&](bool has_enum_value, |
| mojom::RegularEnum enum_value, |
| bool has_mapped_enum_value, |
| TypemappedEnum mapped_enum_value) { |
| EXPECT_FALSE(has_enum_value); |
| EXPECT_TRUE(has_mapped_enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueTwo, mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithEnums( |
| true, mojom::RegularEnum::kThatValue, true, TypemappedEnum::kValueTwo, |
| base::BindLambdaForTesting([&](bool has_enum_value, |
| mojom::RegularEnum enum_value, |
| bool has_mapped_enum_value, |
| TypemappedEnum mapped_enum_value) { |
| EXPECT_TRUE(has_enum_value); |
| EXPECT_EQ(mojom::RegularEnum::kThisValue, enum_value); |
| EXPECT_TRUE(has_mapped_enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueOne, mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| |
| // optional<enum> calling a receiver using legacy bool+enum. |
| { |
| mojo::Remote<mojom::InterfaceV2> remote; |
| mojo::PendingReceiver<mojom::InterfaceV1> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV1Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithEnums( |
| absl::nullopt, absl::nullopt, |
| base::BindLambdaForTesting( |
| [&](absl::optional<mojom::RegularEnum> enum_value, |
| absl::optional<TypemappedEnum> mapped_enum_value) { |
| EXPECT_EQ(absl::nullopt, enum_value); |
| EXPECT_EQ(absl::nullopt, mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithEnums( |
| mojom::RegularEnum::kThisValue, absl::nullopt, |
| base::BindLambdaForTesting( |
| [&](absl::optional<mojom::RegularEnum> enum_value, |
| absl::optional<TypemappedEnum> mapped_enum_value) { |
| EXPECT_EQ(mojom::RegularEnum::kThatValue, enum_value); |
| EXPECT_EQ(absl::nullopt, mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithEnums( |
| absl::nullopt, TypemappedEnum::kValueOne, |
| base::BindLambdaForTesting( |
| [&](absl::optional<mojom::RegularEnum> enum_value, |
| absl::optional<TypemappedEnum> mapped_enum_value) { |
| EXPECT_EQ(absl::nullopt, enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueTwo, mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithEnums( |
| mojom::RegularEnum::kThatValue, TypemappedEnum::kValueTwo, |
| base::BindLambdaForTesting( |
| [&](absl::optional<mojom::RegularEnum> enum_value, |
| absl::optional<TypemappedEnum> mapped_enum_value) { |
| EXPECT_EQ(mojom::RegularEnum::kThisValue, enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueOne, mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| } |
| |
| TEST_F(NullableValueTypes, MethodStructWithEnumsCompatibility) { |
| // Legacy bool+enum calling a receiver using optional<enum> |
| { |
| mojo::Remote<mojom::InterfaceV1> remote; |
| mojo::PendingReceiver<mojom::InterfaceV2> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV2Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithEnums( |
| mojom::CompatibleStructWithEnums::New( |
| false, /* ignored */ mojom::RegularEnum::kThisValue, false, |
| /* ignored */ TypemappedEnum::kValueOne), |
| base::BindLambdaForTesting( |
| [&](mojom::CompatibleStructWithEnumsPtr out) { |
| EXPECT_FALSE(out->has_enum_value); |
| EXPECT_FALSE(out->has_mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithEnums( |
| mojom::CompatibleStructWithEnums::New( |
| true, mojom::RegularEnum::kThisValue, false, |
| /* ignored */ TypemappedEnum::kValueOne), |
| base::BindLambdaForTesting( |
| [&](mojom::CompatibleStructWithEnumsPtr out) { |
| EXPECT_TRUE(out->has_enum_value); |
| EXPECT_EQ(mojom::RegularEnum::kThatValue, out->enum_value); |
| EXPECT_FALSE(out->has_mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithEnums( |
| mojom::CompatibleStructWithEnums::New( |
| false, /* ignored */ mojom::RegularEnum::kThisValue, true, |
| TypemappedEnum::kValueOne), |
| base::BindLambdaForTesting( |
| [&](mojom::CompatibleStructWithEnumsPtr out) { |
| EXPECT_FALSE(out->has_enum_value); |
| EXPECT_TRUE(out->has_mapped_enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueTwo, out->mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithEnums( |
| mojom::CompatibleStructWithEnums::New( |
| true, mojom::RegularEnum::kThatValue, true, |
| TypemappedEnum::kValueTwo), |
| base::BindLambdaForTesting( |
| [&](mojom::CompatibleStructWithEnumsPtr out) { |
| EXPECT_TRUE(out->has_enum_value); |
| EXPECT_EQ(mojom::RegularEnum::kThisValue, out->enum_value); |
| EXPECT_TRUE(out->has_mapped_enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueOne, out->mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| |
| // optional<enum> calling a receiver using legacy bool+enum. |
| { |
| mojo::Remote<mojom::InterfaceV2> remote; |
| mojo::PendingReceiver<mojom::InterfaceV1> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV1Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithEnums( |
| mojom::StructWithEnums::New(absl::nullopt, absl::nullopt), |
| base::BindLambdaForTesting([&](mojom::StructWithEnumsPtr out) { |
| EXPECT_EQ(absl::nullopt, out->enum_value); |
| EXPECT_EQ(absl::nullopt, out->mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithEnums( |
| mojom::StructWithEnums::New(mojom::RegularEnum::kThisValue, |
| absl::nullopt), |
| base::BindLambdaForTesting([&](mojom::StructWithEnumsPtr out) { |
| EXPECT_EQ(mojom::RegularEnum::kThatValue, out->enum_value); |
| EXPECT_EQ(absl::nullopt, out->mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithEnums( |
| mojom::StructWithEnums::New(absl::nullopt, TypemappedEnum::kValueOne), |
| base::BindLambdaForTesting([&](mojom::StructWithEnumsPtr out) { |
| EXPECT_EQ(absl::nullopt, out->enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueTwo, out->mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithEnums( |
| mojom::StructWithEnums::New(mojom::RegularEnum::kThatValue, |
| TypemappedEnum::kValueTwo), |
| base::BindLambdaForTesting([&](mojom::StructWithEnumsPtr out) { |
| EXPECT_EQ(mojom::RegularEnum::kThisValue, out->enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueOne, out->mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| } |
| |
| TEST_F(NullableValueTypes, StructWithNumerics) { |
| { |
| auto input = mojom::StructWithNumerics::New(); |
| input->bool_value = true; |
| input->u8_value = absl::nullopt; |
| input->u16_value = 16; |
| input->u32_value = absl::nullopt; |
| input->u64_value = 64; |
| input->i8_value = -8; |
| input->i16_value = absl::nullopt; |
| input->i32_value = -32; |
| input->i64_value = absl::nullopt; |
| input->float_value = absl::nullopt; |
| input->double_value = -64.0; |
| |
| mojom::StructWithNumericsPtr output; |
| ASSERT_TRUE( |
| SerializeAndDeserialize<mojom::StructWithNumerics>(input, output)); |
| |
| EXPECT_EQ(true, output->bool_value); |
| EXPECT_EQ(absl::nullopt, output->u8_value); |
| EXPECT_EQ(16u, output->u16_value); |
| EXPECT_EQ(absl::nullopt, output->u32_value); |
| EXPECT_EQ(64u, output->u64_value); |
| EXPECT_EQ(-8, output->i8_value); |
| EXPECT_EQ(absl::nullopt, output->i16_value); |
| EXPECT_EQ(-32, output->i32_value); |
| EXPECT_EQ(absl::nullopt, output->i64_value); |
| EXPECT_EQ(absl::nullopt, output->float_value); |
| EXPECT_EQ(-64.0, output->double_value); |
| } |
| |
| { |
| auto input = mojom::StructWithNumerics::New(); |
| input->bool_value = absl::nullopt; |
| input->u8_value = 8; |
| input->u16_value = absl::nullopt; |
| input->u32_value = 32; |
| input->u64_value = absl::nullopt; |
| input->i8_value = absl::nullopt; |
| input->i16_value = -16; |
| input->i32_value = absl::nullopt; |
| input->i64_value = -64; |
| input->float_value = -32.0f; |
| input->double_value = absl::nullopt; |
| |
| mojom::StructWithNumericsPtr output; |
| ASSERT_TRUE( |
| SerializeAndDeserialize<mojom::StructWithNumerics>(input, output)); |
| |
| EXPECT_EQ(absl::nullopt, output->bool_value); |
| EXPECT_EQ(8u, output->u8_value); |
| EXPECT_EQ(absl::nullopt, output->u16_value); |
| EXPECT_EQ(32u, output->u32_value); |
| EXPECT_EQ(absl::nullopt, output->u64_value); |
| EXPECT_EQ(absl::nullopt, output->i8_value); |
| EXPECT_EQ(-16, output->i16_value); |
| EXPECT_EQ(absl::nullopt, output->i32_value); |
| EXPECT_EQ(-64, output->i64_value); |
| EXPECT_EQ(-32.0f, output->float_value); |
| EXPECT_EQ(absl::nullopt, output->double_value); |
| } |
| } |
| |
| TEST_F(NullableValueTypes, MethodNumericArgsCompatibility) { |
| // Legacy bool+enum calling a receiver using optional<enum> |
| { |
| mojo::Remote<mojom::InterfaceV1> remote; |
| mojo::PendingReceiver<mojom::InterfaceV2> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV2Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithNumerics( |
| true, true, false, /* ignored */ uint8_t{0}, true, uint16_t{16}, |
| false, |
| /* ignored */ uint32_t{0}, true, uint64_t{64}, true, int8_t{-8}, |
| false, /* ignored */ int16_t{0}, true, int32_t{-32}, false, |
| int64_t{0}, false, /* ignored */ 0.0f, true, -64.0, |
| base::BindLambdaForTesting( |
| [&](bool has_bool_value, bool bool_value, bool has_u8_value, |
| uint8_t u8_value, bool has_u16_value, uint16_t u16_value, |
| bool has_u32_value, uint32_t u32_value, bool has_u64_value, |
| uint64_t u64_value, bool has_i8_value, int8_t i8_value, |
| bool has_i16_value, int16_t i16_value, bool has_i32_value, |
| int32_t i32_value, bool has_i64_value, int64_t i64_value, |
| bool has_float_value, float float_value, |
| bool has_double_value, double double_value) { |
| EXPECT_TRUE(has_bool_value); |
| EXPECT_EQ(false, bool_value); |
| EXPECT_FALSE(has_u8_value); |
| EXPECT_TRUE(has_u16_value); |
| // Note: the seemingly more obvious ~uint16_t{16} is not used |
| // here because using ~ when sizeof(integer) < sizeof(int) |
| // automatically promotes to an int. 🙃 |
| EXPECT_EQ(uint16_t{0xffef}, u16_value); |
| EXPECT_FALSE(has_u32_value); |
| EXPECT_TRUE(has_u64_value); |
| EXPECT_EQ(~uint64_t{64}, u64_value); |
| EXPECT_TRUE(has_i8_value); |
| EXPECT_EQ(8, i8_value); |
| EXPECT_FALSE(has_i16_value); |
| EXPECT_TRUE(has_i32_value); |
| EXPECT_EQ(32, i32_value); |
| EXPECT_FALSE(has_i64_value); |
| EXPECT_FALSE(has_float_value); |
| EXPECT_TRUE(has_double_value); |
| EXPECT_EQ(128.0, double_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithNumerics( |
| false, /* ignored */ false, true, uint8_t{8}, false, |
| /* ignored */ uint16_t{0}, true, uint32_t{32}, false, |
| /* ignored */ uint64_t{0}, false, |
| /* ignored */ int8_t{0}, true, int16_t{-16}, false, |
| /* ignored */ int32_t{0}, true, int64_t{-64}, true, -32.0f, false, |
| /* ignored */ -0.0, |
| base::BindLambdaForTesting( |
| [&](bool has_bool_value, bool bool_value, bool has_u8_value, |
| uint8_t u8_value, bool has_u16_value, uint16_t u16_value, |
| bool has_u32_value, uint32_t u32_value, bool has_u64_value, |
| uint64_t u64_value, bool has_i8_value, int8_t i8_value, |
| bool has_i16_value, int16_t i16_value, bool has_i32_value, |
| int32_t i32_value, bool has_i64_value, int64_t i64_value, |
| bool has_float_value, float float_value, |
| bool has_double_value, double double_value) { |
| EXPECT_FALSE(has_bool_value); |
| EXPECT_TRUE(has_u8_value); |
| // Note: the seemingly more obvious ~uint8_t{8} is not used |
| // here because using ~ when sizeof(integer) < sizeof(int) |
| // automatically promotes to an int. 🙃 |
| EXPECT_EQ(uint8_t{0xf7}, u8_value); |
| EXPECT_FALSE(has_u16_value); |
| EXPECT_TRUE(has_u32_value); |
| EXPECT_EQ(~uint32_t{32}, u32_value); |
| EXPECT_FALSE(has_u64_value); |
| EXPECT_FALSE(has_i8_value); |
| EXPECT_TRUE(has_i16_value); |
| EXPECT_EQ(16, i16_value); |
| EXPECT_FALSE(has_i32_value); |
| EXPECT_TRUE(has_i64_value); |
| EXPECT_EQ(64, i64_value); |
| EXPECT_TRUE(has_float_value); |
| EXPECT_EQ(64.0, float_value); |
| EXPECT_FALSE(has_double_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| |
| // optional<enum> calling a receiver using legacy bool+enum. |
| { |
| mojo::Remote<mojom::InterfaceV2> remote; |
| mojo::PendingReceiver<mojom::InterfaceV1> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV1Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithNumerics( |
| true, absl::nullopt, uint16_t{16}, absl::nullopt, uint64_t{64}, |
| int8_t{-8}, absl::nullopt, int32_t{-32}, absl::nullopt, absl::nullopt, |
| -64.0, |
| base::BindLambdaForTesting([&](absl::optional<bool> bool_value, |
| absl::optional<uint8_t> u8_value, |
| absl::optional<uint16_t> u16_value, |
| absl::optional<uint32_t> u32_value, |
| absl::optional<uint64_t> u64_value, |
| absl::optional<int8_t> i8_value, |
| absl::optional<int16_t> i16_value, |
| absl::optional<int32_t> i32_value, |
| absl::optional<int64_t> i64_value, |
| absl::optional<float> float_value, |
| absl::optional<double> double_value) { |
| EXPECT_EQ(false, bool_value); |
| EXPECT_EQ(absl::nullopt, u8_value); |
| // Note: the seemingly more obvious ~uint16_t{16} is not used |
| // here because using ~ when sizeof(integer) < sizeof(int) |
| // automatically promotes to an int. 🙃 |
| EXPECT_EQ(uint16_t{0xffef}, u16_value); |
| EXPECT_EQ(absl::nullopt, u32_value); |
| EXPECT_EQ(~uint64_t{64}, u64_value); |
| EXPECT_EQ(8, i8_value); |
| EXPECT_EQ(absl::nullopt, i16_value); |
| EXPECT_EQ(32, i32_value); |
| EXPECT_EQ(absl::nullopt, i64_value); |
| EXPECT_EQ(absl::nullopt, float_value); |
| EXPECT_EQ(128.0, double_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithNumerics( |
| absl::nullopt, uint8_t{8}, absl::nullopt, uint32_t{32}, absl::nullopt, |
| absl::nullopt, int16_t{-16}, absl::nullopt, int64_t{-64}, -32.0f, |
| absl::nullopt, |
| base::BindLambdaForTesting([&](absl::optional<bool> bool_value, |
| absl::optional<uint8_t> u8_value, |
| absl::optional<uint16_t> u16_value, |
| absl::optional<uint32_t> u32_value, |
| absl::optional<uint64_t> u64_value, |
| absl::optional<int8_t> i8_value, |
| absl::optional<int16_t> i16_value, |
| absl::optional<int32_t> i32_value, |
| absl::optional<int64_t> i64_value, |
| absl::optional<float> float_value, |
| absl::optional<double> double_value) { |
| EXPECT_EQ(absl::nullopt, bool_value); |
| // Note: the seemingly more obvious ~uint8_t{8} is not used |
| // here because using ~ when sizeof(integer) < sizeof(int) |
| // automatically promotes to an int. 🙃 |
| EXPECT_EQ(uint8_t{0xf7}, u8_value); |
| EXPECT_EQ(absl::nullopt, u16_value); |
| EXPECT_EQ(~uint32_t{32}, u32_value); |
| EXPECT_EQ(absl::nullopt, u64_value); |
| EXPECT_EQ(absl::nullopt, i8_value); |
| EXPECT_EQ(16, i16_value); |
| EXPECT_EQ(absl::nullopt, i32_value); |
| EXPECT_EQ(64, i64_value); |
| EXPECT_EQ(64.0, float_value); |
| EXPECT_EQ(absl::nullopt, double_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| } |
| |
| TEST_F(NullableValueTypes, MethodStructWithNumericsCompatibility) { |
| // Legacy bool+enum calling a receiver using optional<enum> |
| { |
| mojo::Remote<mojom::InterfaceV1> remote; |
| mojo::PendingReceiver<mojom::InterfaceV2> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV2Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithNumerics( |
| mojom::CompatibleStructWithNumerics::New( |
| true, true, false, /* ignored */ uint8_t{0}, true, uint16_t{16}, |
| false, |
| /* ignored */ uint32_t{0}, true, uint64_t{64}, true, int8_t{-8}, |
| false, /* ignored */ int16_t{0}, true, int32_t{-32}, false, |
| int64_t{0}, false, /* ignored */ 0.0f, true, -64.0), |
| base::BindLambdaForTesting( |
| [&](mojom::CompatibleStructWithNumericsPtr out) { |
| EXPECT_TRUE(out->has_bool_value); |
| EXPECT_EQ(false, out->bool_value); |
| EXPECT_FALSE(out->has_u8_value); |
| EXPECT_TRUE(out->has_u16_value); |
| // Note: the seemingly more obvious ~uint16_t{16} is not used |
| // here because using ~ when sizeof(integer) < sizeof(int) |
| // automatically promotes to an int. 🙃 |
| EXPECT_EQ(uint16_t{0xffef}, out->u16_value); |
| EXPECT_FALSE(out->has_u32_value); |
| EXPECT_TRUE(out->has_u64_value); |
| EXPECT_EQ(~uint64_t{64}, out->u64_value); |
| EXPECT_TRUE(out->has_i8_value); |
| EXPECT_EQ(8, out->i8_value); |
| EXPECT_FALSE(out->has_i16_value); |
| EXPECT_TRUE(out->has_i32_value); |
| EXPECT_EQ(32, out->i32_value); |
| EXPECT_FALSE(out->has_i64_value); |
| EXPECT_FALSE(out->has_float_value); |
| EXPECT_TRUE(out->has_double_value); |
| EXPECT_EQ(128.0, out->double_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithNumerics( |
| mojom::CompatibleStructWithNumerics::New( |
| false, /* ignored */ false, true, uint8_t{8}, false, |
| /* ignored */ uint16_t{0}, true, uint32_t{32}, false, |
| /* ignored */ uint64_t{0}, false, |
| /* ignored */ int8_t{0}, true, int16_t{-16}, false, |
| /* ignored */ int32_t{0}, true, int64_t{-64}, true, -32.0f, false, |
| /* ignored */ -0.0), |
| base::BindLambdaForTesting( |
| [&](mojom::CompatibleStructWithNumericsPtr out) { |
| EXPECT_FALSE(out->has_bool_value); |
| EXPECT_TRUE(out->has_u8_value); |
| // Note: the seemingly more obvious ~uint8_t{8} is not used |
| // here because using ~ when sizeof(integer) < sizeof(int) |
| // automatically promotes to an int. 🙃 |
| EXPECT_EQ(uint8_t{0xf7}, out->u8_value); |
| EXPECT_FALSE(out->has_u16_value); |
| EXPECT_TRUE(out->has_u32_value); |
| EXPECT_EQ(~uint32_t{32}, out->u32_value); |
| EXPECT_FALSE(out->has_u64_value); |
| EXPECT_FALSE(out->has_i8_value); |
| EXPECT_TRUE(out->has_i16_value); |
| EXPECT_EQ(16, out->i16_value); |
| EXPECT_FALSE(out->has_i32_value); |
| EXPECT_TRUE(out->has_i64_value); |
| EXPECT_EQ(64, out->i64_value); |
| EXPECT_TRUE(out->has_float_value); |
| EXPECT_EQ(64.0, out->float_value); |
| EXPECT_FALSE(out->has_double_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| |
| // optional<enum> calling a receiver using legacy bool+enum. |
| { |
| mojo::Remote<mojom::InterfaceV2> remote; |
| mojo::PendingReceiver<mojom::InterfaceV1> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV1Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithNumerics( |
| mojom::StructWithNumerics::New( |
| true, absl::nullopt, uint16_t{16}, absl::nullopt, uint64_t{64}, |
| int8_t{-8}, absl::nullopt, int32_t{-32}, absl::nullopt, |
| absl::nullopt, -64.0), |
| base::BindLambdaForTesting([&](mojom::StructWithNumericsPtr out) { |
| EXPECT_EQ(false, out->bool_value); |
| EXPECT_EQ(absl::nullopt, out->u8_value); |
| // Note: the seemingly more obvious ~uint16_t{16} is not used |
| // here because using ~ when sizeof(integer) < sizeof(int) |
| // automatically promotes to an int. 🙃 |
| EXPECT_EQ(uint16_t{0xffef}, out->u16_value); |
| EXPECT_EQ(absl::nullopt, out->u32_value); |
| EXPECT_EQ(~uint64_t{64}, out->u64_value); |
| EXPECT_EQ(8, out->i8_value); |
| EXPECT_EQ(absl::nullopt, out->i16_value); |
| EXPECT_EQ(32, out->i32_value); |
| EXPECT_EQ(absl::nullopt, out->i64_value); |
| EXPECT_EQ(absl::nullopt, out->float_value); |
| EXPECT_EQ(128.0, out->double_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithStructWithNumerics( |
| mojom::StructWithNumerics::New( |
| absl::nullopt, uint8_t{8}, absl::nullopt, uint32_t{32}, |
| absl::nullopt, absl::nullopt, int16_t{-16}, absl::nullopt, |
| int64_t{-64}, -32.0f, absl::nullopt), |
| base::BindLambdaForTesting([&](mojom::StructWithNumericsPtr out) { |
| EXPECT_EQ(absl::nullopt, out->bool_value); |
| // Note: the seemingly more obvious ~uint8_t{8} is not used |
| // here because using ~ when sizeof(integer) < sizeof(int) |
| // automatically promotes to an int. 🙃 |
| EXPECT_EQ(uint8_t{0xf7}, out->u8_value); |
| EXPECT_EQ(absl::nullopt, out->u16_value); |
| EXPECT_EQ(~uint32_t{32}, out->u32_value); |
| EXPECT_EQ(absl::nullopt, out->u64_value); |
| EXPECT_EQ(absl::nullopt, out->i8_value); |
| EXPECT_EQ(16, out->i16_value); |
| EXPECT_EQ(absl::nullopt, out->i32_value); |
| EXPECT_EQ(64, out->i64_value); |
| EXPECT_EQ(64.0, out->float_value); |
| EXPECT_EQ(absl::nullopt, out->double_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| } |
| |
| TEST_F(NullableValueTypes, Versioning) { |
| // Baseline: V1 to V1. |
| { |
| mojo::Remote<mojom::InterfaceV1> remote; |
| mojo::PendingReceiver<mojom::InterfaceV1> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV1Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithVersionedArgs( |
| base::BindLambdaForTesting([&]() { loop.Quit(); })); |
| loop.Run(); |
| } |
| |
| { |
| auto expected = mojom::VersionedStructV1::New(); |
| base::RunLoop loop; |
| remote->MethodWithVersionedStruct( |
| expected.Clone(), |
| base::BindLambdaForTesting([&](mojom::VersionedStructV1Ptr out) { |
| EXPECT_EQ(expected, out); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| |
| // V1 to V2. |
| { |
| mojo::Remote<mojom::InterfaceV1> remote; |
| mojo::PendingReceiver<mojom::InterfaceV2> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV2Impl impl(std::move(receiver), CallerVersion::kV1); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithVersionedArgs( |
| base::BindLambdaForTesting([&]() { loop.Quit(); })); |
| loop.Run(); |
| } |
| |
| { |
| auto expected = mojom::VersionedStructV1::New(); |
| base::RunLoop loop; |
| remote->MethodWithVersionedStruct( |
| expected.Clone(), |
| base::BindLambdaForTesting([&](mojom::VersionedStructV1Ptr out) { |
| EXPECT_EQ(expected, out); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| |
| // V2 to V1. |
| { |
| mojo::Remote<mojom::InterfaceV2> remote; |
| mojo::PendingReceiver<mojom::InterfaceV1> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV1Impl impl(std::move(receiver)); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithVersionedArgs( |
| true, uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, int8_t{-16}, |
| int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, -512.0, |
| mojom::RegularEnum::kThisValue, TypemappedEnum::kValueTwo, |
| base::BindLambdaForTesting( |
| [&](absl::optional<bool> out_bool_value, |
| absl::optional<uint8_t> out_u8_value, |
| absl::optional<uint16_t> out_u16_value, |
| absl::optional<uint32_t> out_u32_value, |
| absl::optional<uint64_t> out_u64_value, |
| absl::optional<int8_t> out_i8_value, |
| absl::optional<int16_t> out_i16_value, |
| absl::optional<int32_t> out_i32_value, |
| absl::optional<int64_t> out_i64_value, |
| absl::optional<float> out_float_value, |
| absl::optional<double> out_double_value, |
| absl::optional<mojom::RegularEnum> out_enum_value, |
| absl::optional<TypemappedEnum> out_mapped_enum_value) { |
| // An implementation based on the V1 interface will not know |
| // about the new arguments, so they should all equal |
| // absl::nullopt. |
| EXPECT_EQ(absl::nullopt, out_bool_value); |
| EXPECT_EQ(absl::nullopt, out_u8_value); |
| EXPECT_EQ(absl::nullopt, out_u16_value); |
| EXPECT_EQ(absl::nullopt, out_u32_value); |
| EXPECT_EQ(absl::nullopt, out_u64_value); |
| EXPECT_EQ(absl::nullopt, out_i8_value); |
| EXPECT_EQ(absl::nullopt, out_i16_value); |
| EXPECT_EQ(absl::nullopt, out_i32_value); |
| EXPECT_EQ(absl::nullopt, out_i64_value); |
| EXPECT_EQ(absl::nullopt, out_float_value); |
| EXPECT_EQ(absl::nullopt, out_double_value); |
| EXPECT_EQ(absl::nullopt, out_enum_value); |
| EXPECT_EQ(absl::nullopt, out_mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithVersionedStruct( |
| mojom::VersionedStructV2::New( |
| true, uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, |
| int8_t{-16}, int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, |
| -512.0, mojom::RegularEnum::kThisValue, |
| TypemappedEnum::kValueTwo), |
| base::BindLambdaForTesting([&](mojom::VersionedStructV2Ptr out) { |
| // An implementation based on the V1 interface will not know |
| // about the new arguments, so they should all equal |
| // absl::nullopt. |
| EXPECT_EQ(absl::nullopt, out->bool_value); |
| EXPECT_EQ(absl::nullopt, out->u8_value); |
| EXPECT_EQ(absl::nullopt, out->u16_value); |
| EXPECT_EQ(absl::nullopt, out->u32_value); |
| EXPECT_EQ(absl::nullopt, out->u64_value); |
| EXPECT_EQ(absl::nullopt, out->i8_value); |
| EXPECT_EQ(absl::nullopt, out->i16_value); |
| EXPECT_EQ(absl::nullopt, out->i32_value); |
| EXPECT_EQ(absl::nullopt, out->i64_value); |
| EXPECT_EQ(absl::nullopt, out->float_value); |
| EXPECT_EQ(absl::nullopt, out->double_value); |
| EXPECT_EQ(absl::nullopt, out->enum_value); |
| EXPECT_EQ(absl::nullopt, out->mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| |
| // V2 to V2. |
| { |
| mojo::Remote<mojom::InterfaceV2> remote; |
| mojo::PendingReceiver<mojom::InterfaceV2> receiver( |
| remote.BindNewPipeAndPassReceiver().PassPipe()); |
| InterfaceV2Impl impl(std::move(receiver), CallerVersion::kV2); |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithVersionedArgs( |
| true, uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, int8_t{-16}, |
| int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, -512.0, |
| mojom::RegularEnum::kThisValue, TypemappedEnum::kValueTwo, |
| base::BindLambdaForTesting( |
| [&](absl::optional<bool> out_bool_value, |
| absl::optional<uint8_t> out_u8_value, |
| absl::optional<uint16_t> out_u16_value, |
| absl::optional<uint32_t> out_u32_value, |
| absl::optional<uint64_t> out_u64_value, |
| absl::optional<int8_t> out_i8_value, |
| absl::optional<int16_t> out_i16_value, |
| absl::optional<int32_t> out_i32_value, |
| absl::optional<int64_t> out_i64_value, |
| absl::optional<float> out_float_value, |
| absl::optional<double> out_double_value, |
| absl::optional<mojom::RegularEnum> out_enum_value, |
| absl::optional<TypemappedEnum> out_mapped_enum_value) { |
| EXPECT_EQ(false, out_bool_value); |
| EXPECT_EQ(uint8_t{128}, out_u8_value); |
| EXPECT_EQ(uint16_t{64}, out_u16_value); |
| EXPECT_EQ(uint32_t{32}, out_u32_value); |
| EXPECT_EQ(uint64_t{16}, out_u64_value); |
| EXPECT_EQ(int8_t{-8}, out_i8_value); |
| EXPECT_EQ(int16_t{-4}, out_i16_value); |
| EXPECT_EQ(int32_t{-2}, out_i32_value); |
| EXPECT_EQ(int32_t{-1}, out_i64_value); |
| EXPECT_EQ(-0.5f, out_float_value); |
| EXPECT_EQ(0.25, out_double_value); |
| EXPECT_EQ(mojom::RegularEnum::kThatValue, out_enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueOne, out_mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| |
| { |
| base::RunLoop loop; |
| remote->MethodWithVersionedStruct( |
| mojom::VersionedStructV2::New( |
| true, uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, |
| int8_t{-16}, int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, |
| -512.0, mojom::RegularEnum::kThisValue, |
| TypemappedEnum::kValueTwo), |
| base::BindLambdaForTesting([&](mojom::VersionedStructV2Ptr out) { |
| EXPECT_EQ(false, out->bool_value); |
| EXPECT_EQ(uint8_t{128}, out->u8_value); |
| EXPECT_EQ(uint16_t{64}, out->u16_value); |
| EXPECT_EQ(uint32_t{32}, out->u32_value); |
| EXPECT_EQ(uint64_t{16}, out->u64_value); |
| EXPECT_EQ(int8_t{-8}, out->i8_value); |
| EXPECT_EQ(int16_t{-4}, out->i16_value); |
| EXPECT_EQ(int32_t{-2}, out->i32_value); |
| EXPECT_EQ(int32_t{-1}, out->i64_value); |
| EXPECT_EQ(-0.5f, out->float_value); |
| EXPECT_EQ(0.25, out->double_value); |
| EXPECT_EQ(mojom::RegularEnum::kThatValue, out->enum_value); |
| EXPECT_EQ(TypemappedEnum::kValueOne, out->mapped_enum_value); |
| loop.Quit(); |
| })); |
| loop.Run(); |
| } |
| } |
| } |
| |
| } // namespace |
| } // namespace mojo::test::_and_enums_unittest |