| // Copyright 2020 The Fuchsia 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 <fidl/fuchsia.sysmem/cpp/fidl.h> |
| #include <fidl/fuchsia.sysmem2/cpp/fidl.h> |
| #include <lib/fidl/cpp/message_part.h> |
| #include <lib/fidl/cpp/wire/message.h> |
| #include <lib/fidl/cpp/wire/traits.h> |
| #include <lib/sysmem-version/sysmem-version.h> |
| |
| #include <iterator> |
| #include <memory> |
| #include <optional> |
| #include <random> |
| #include <type_traits> |
| #include <vector> |
| |
| #include <fbl/array.h> |
| #include <zxtest/zxtest.h> |
| |
| namespace v1 = fuchsia_sysmem; |
| namespace v2 = fuchsia_sysmem2; |
| |
| namespace { |
| |
| constexpr uint32_t kRunCount = 300; |
| |
| // IsNaturalFidlType<> - This is an ad-hoc detection of whether a given FidlType is a natural fidl |
| // type. Types which are the same type regardless of natural vs. wire will have value true, as the |
| // type is valid for use as a natural FIDL type - such types are essentially both natural and wire. |
| // |
| // This currently relies on all non-aggregate FIDL types being shared between natural and wire. |
| // |
| // Ideally the FIDL generated code would expose a way to determine this more cleanly / officially. |
| // |
| // We rely on FIDL generated code to fail to compile if we try to use fidl::ToWire() or |
| // fidl::ToNatural() without including natural_types.h, rather than having any static_assert() in |
| // any of these templates, since static_assert() in a template tends to make that template unusable |
| // for further SFINAE. |
| template <typename FidlType, typename enable = void> |
| class IsNaturalFidlType : public std::false_type {}; |
| // For aggregate FIDL types are only natural types if they lack the wire TypeTraits<>. |
| template <typename FidlType> |
| class IsNaturalFidlType<FidlType, std::enable_if_t<fidl::IsFidlType<FidlType>::value && |
| fidl::IsFidlObject<FidlType>::value && |
| !fidl::IsWire<FidlType>::value>> |
| : public std::true_type {}; |
| // Non-aggregate FIDL types are shared between natural and wire, so IsNaturalFidlType<> is true for |
| // non-aggregate types. |
| template <typename FidlType> |
| class IsNaturalFidlType<FidlType, std::enable_if_t<fidl::IsFidlType<FidlType>::value && |
| !fidl::IsFidlObject<FidlType>::value>> |
| : public std::true_type {}; |
| |
| // Some compile-time tests of IsNaturalFidlType<> to make sure it continues to do what we need in |
| // this file. |
| |
| // Natural vs. wire distinction for a FIDL struct. |
| static_assert(IsNaturalFidlType<fuchsia_sysmem::BufferUsage>::value); |
| static_assert(!IsNaturalFidlType<fuchsia_sysmem::wire::BufferUsage>::value); |
| |
| // Natural vs. wire distinction for a FIDL struct with a handle: |
| static_assert(IsNaturalFidlType<fuchsia_sysmem::VmoBuffer>::value); |
| static_assert(!IsNaturalFidlType<fuchsia_sysmem::wire::VmoBuffer>::value); |
| |
| // Natural vs. wire distinction for a FIDL table. |
| static_assert(IsNaturalFidlType<fuchsia_sysmem2::BufferUsage>::value); |
| static_assert(!IsNaturalFidlType<fuchsia_sysmem2::wire::BufferUsage>::value); |
| |
| // Natural vs. wire distinction for a FIDL table with handle(s): |
| static_assert(IsNaturalFidlType<fuchsia_sysmem2::BufferCollectionInfo>::value); |
| static_assert(!IsNaturalFidlType<fuchsia_sysmem2::wire::BufferCollectionInfo>::value); |
| |
| // Natural and wire use the same type for types whose underlying type is a primitive type |
| // (non-aggregate / non-IsFidlObject<> FIDL types), so in this sense both "::wire::" and |
| // non-"::wire::" are natural types because such types are both natural and wire (exact same type). |
| static_assert(std::is_same_v<fuchsia_sysmem::HeapType, fuchsia_sysmem::wire::HeapType>); |
| static_assert(IsNaturalFidlType<fuchsia_sysmem::HeapType>::value); |
| static_assert(IsNaturalFidlType<fuchsia_sysmem::wire::HeapType>::value); |
| static_assert(IsNaturalFidlType<uint32_t>::value); |
| |
| // GetWireType - determines the wire type corresponding to a fidl type. If FidlType is is a natural |
| // type and not a wire type, the result is the corresponding wire type. If FidlType is both a |
| // natural and wire type, the result is FidlType. If FidlType is a wire type and not a natural type |
| // the result is FidlType. |
| // |
| // If the "type" member is missing, that means IsFidlType<FidlType> is false. Having no type field |
| // is better than a static_assert() in case of use of GetWireType<> in any further SFINAE. |
| template <typename FidlType, typename enable = void> |
| class GetWireType { |
| // Intentionally no "type" member to induce compilation failure or substitution failures if used |
| // in a SFINAE context. FWIW, the latter wouldn't allow for intentional substitution failure if |
| // we had static_assert(fidl::IsFidlType<FidlType>::value) here, so we instead rely on |
| // fidl::ToWire() to complain if a non-FIDL type is passed in. |
| }; |
| template <typename FidlType> |
| class GetWireType<FidlType, std::enable_if_t<fidl::IsFidlType<FidlType>::value && |
| IsNaturalFidlType<FidlType>::value>> { |
| public: |
| using type = decltype((fidl::ToWire(*static_cast<fidl::Arena<512>*>(nullptr), |
| std::move(*static_cast<FidlType*>(nullptr))))); |
| }; |
| template <typename FidlType> |
| class GetWireType<FidlType, std::enable_if_t<fidl::IsFidlType<FidlType>::value && |
| !IsNaturalFidlType<FidlType>::value>> { |
| public: |
| using type = FidlType; |
| }; |
| |
| static_assert(std::is_same_v<fuchsia_sysmem::wire::BufferUsage, |
| GetWireType<fuchsia_sysmem::BufferUsage>::type>); |
| static_assert( |
| std::is_same_v<fuchsia_sysmem::wire::VmoBuffer, GetWireType<fuchsia_sysmem::VmoBuffer>::type>); |
| static_assert( |
| std::is_same_v<fuchsia_sysmem::HeapType, GetWireType<fuchsia_sysmem::wire::HeapType>::type>); |
| static_assert(std::is_same_v<uint32_t, GetWireType<uint32_t>::type>); |
| |
| // LinearSnap - makes and holds a flat serialization for bit-for-bit comparison purposes. |
| // |
| // The FidlType can be a wire type or a natural type. |
| template <typename FidlType> |
| class LinearSnap { |
| static_assert(fidl::IsFidlType<FidlType>::value); |
| using WireType = typename GetWireType<FidlType>::type; |
| using NaturalType = |
| std::conditional_t<std::is_same_v<FidlType, WireType>, |
| decltype(fidl::ToNatural(std::declval<WireType>())), FidlType>; |
| |
| public: |
| static constexpr size_t kMaxDataSize = 64 * 1024; |
| static constexpr size_t kMaxHandleCount = 1024; |
| |
| static std::unique_ptr<LinearSnap> MoveFrom(FidlType&& to_move_in) { |
| return std::unique_ptr<LinearSnap<FidlType>>(new LinearSnap(std::move(to_move_in))); |
| } |
| |
| // Get a reference to a serialized then deserialized instance that should contain the same logical |
| // data as the initially moved-in instance. |
| // |
| // This reference can't be used beyond the lifetime of the LinearSnap instance. |
| FidlType& value() { return decoded_value_.value(); } |
| |
| cpp20::span<const uint8_t> snap_bytes() const { return cpp20::span(snap_data_); } |
| |
| cpp20::span<const zx_handle_t> snap_handles() const { return cpp20::span(snap_handles_); } |
| |
| cpp20::span<const fidl_channel_handle_metadata_t> snap_handle_metadata() const { |
| return cpp20::span(snap_handle_metadata_); |
| } |
| |
| private: |
| explicit LinearSnap(FidlType&& to_move_in) { |
| // Always consume to_move_in, along with converting from wire to natural as needed. |
| NaturalType natural; |
| if constexpr (std::is_same_v<FidlType, WireType>) { |
| natural = fidl::ToNatural(std::move(to_move_in)); |
| } else { |
| natural = std::move(to_move_in); |
| } |
| |
| fidl::OwnedEncodeResult encoded = fidl::StandaloneEncode(std::move(natural)); |
| ZX_ASSERT(encoded.message().ok()); |
| fidl::OutgoingMessage& outgoing_message = encoded.message(); |
| fidl::OutgoingMessage::CopiedBytes outgoing_message_bytes = outgoing_message.CopyBytes(); |
| snap_data_ = {outgoing_message_bytes.data(), |
| outgoing_message_bytes.data() + outgoing_message_bytes.size()}; |
| snap_handles_ = {outgoing_message.handles(), |
| outgoing_message.handles() + outgoing_message.handle_actual()}; |
| snap_handle_metadata_ = {outgoing_message.handle_metadata<fidl::internal::ChannelTransport>(), |
| outgoing_message.handle_metadata<fidl::internal::ChannelTransport>() + |
| outgoing_message.handle_actual()}; |
| |
| fidl::OutgoingToEncodedMessage outgoing_to_encoded_result_{outgoing_message}; |
| ZX_ASSERT(outgoing_to_encoded_result_.ok()); |
| fit::result decoded = fidl::StandaloneDecode<NaturalType>( |
| std::move(outgoing_to_encoded_result_.message()), encoded.wire_format_metadata()); |
| ZX_ASSERT(decoded.is_ok()); |
| |
| if constexpr (std::is_same_v<FidlType, WireType>) { |
| // Syntactically this is moving, but the storage is really still shared with arena_; in any |
| // case both are still members of LinearSnap so both are tied to lifetime of LinearSnap. |
| decoded_value_.emplace(fidl::ToWire(arena_, std::move(decoded.value()))); |
| } else { |
| // This really does move out of decoded_, but decoded_value_ still only lasts as long as |
| // LinearSnap. |
| decoded_value_.emplace(std::move(decoded.value())); |
| } |
| } |
| |
| std::vector<uint8_t> snap_data_; |
| std::vector<zx_handle_t> snap_handles_; |
| std::vector<fidl_channel_handle_metadata_t> snap_handle_metadata_; |
| |
| // when FidlType == WireType, holds out-of-line data and handles in the decoded value. |
| fidl::Arena<> arena_; |
| // when FidlType == WireType, shares storage with |arena_|. |
| std::optional<FidlType> decoded_value_; |
| }; |
| |
| template <typename FidlType> |
| std::unique_ptr<LinearSnap<FidlType>> SnapMoveFrom(FidlType&& to_move_in) { |
| return LinearSnap<FidlType>::MoveFrom(std::move(to_move_in)); |
| } |
| |
| template <typename FidlType> |
| bool IsEqualImpl(const LinearSnap<FidlType>& a, const LinearSnap<FidlType>& b, bool by_koid) { |
| if (a.snap_bytes().size() != b.snap_bytes().size()) { |
| return false; |
| } |
| if (0 != memcmp(a.snap_bytes().data(), b.snap_bytes().data(), a.snap_bytes().size())) { |
| return false; |
| } |
| if (a.snap_handles().size() != b.snap_handles().size()) { |
| return false; |
| } |
| if (!by_koid) { |
| if (0 != memcmp(a.snap_handles().data(), b.snap_handles().data(), |
| a.snap_handles().size() * sizeof(zx_handle_t))) { |
| return false; |
| } |
| if (0 != memcmp(a.snap_handle_metadata().data(), b.snap_handle_metadata().data(), |
| a.snap_handle_metadata().size() * sizeof(fidl_channel_handle_metadata_t))) { |
| return false; |
| } |
| } else { |
| for (uint32_t i = 0; i < a.snap_handles().size(); ++i) { |
| zx_info_handle_basic_t a_info{}; |
| zx_info_handle_basic_t b_info{}; |
| ZX_ASSERT(ZX_OK == zx_object_get_info(a.snap_handles()[i], ZX_INFO_HANDLE_BASIC, &a_info, |
| sizeof(a_info), nullptr, nullptr)); |
| ZX_ASSERT(ZX_OK == zx_object_get_info(b.snap_handles()[i], ZX_INFO_HANDLE_BASIC, &b_info, |
| sizeof(a_info), nullptr, nullptr)); |
| if (a_info.koid != b_info.koid) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| template <typename FidlType> |
| bool IsEqual(const LinearSnap<FidlType>& a, const LinearSnap<FidlType>& b) { |
| return IsEqualImpl(a, b, false); |
| } |
| |
| template <typename FidlType> |
| bool IsEqualByKoid(const LinearSnap<FidlType>& a, const LinearSnap<FidlType>& b) { |
| return IsEqualImpl(a, b, true); |
| } |
| |
| std::random_device random_device; |
| std::mt19937 prng(random_device()); |
| |
| template <typename T, std::enable_if_t<!std::is_same_v<T, bool>, bool> = true> |
| void random(T* field) { |
| // If one of these complains, consider adding a random<>() specialization below. |
| static_assert(std::is_integral<T>::value); |
| static_assert(!std::is_enum<T>::value); |
| |
| static std::uniform_int_distribution distribution(std::numeric_limits<T>::min(), |
| std::numeric_limits<T>::max()); |
| while (true) { |
| *field = distribution(prng); |
| // Avoid picking 0, because that'd cause fields to be set or not-set inconsistently, which would |
| // likely cause occasional test flakes. |
| if (*field == 0) { |
| continue; |
| } |
| return; |
| } |
| } |
| |
| void random(bool* field) { |
| // Always return true because zero/false will never be set in the general `random` implementation. |
| *field = true; |
| } |
| |
| template <> |
| void random<v1::HeapType>(v1::HeapType* field) { |
| // TODO(https://fxbug.dev/42130439): Use generated-code array of valid values instead, when/if |
| // available. |
| static constexpr uint64_t valid[] = { |
| /*SYSTEM_RAM =*/0u, |
| /*AMLOGIC_SECURE =*/1152921504606912512u, |
| /*AMLOGIC_SECURE_VDEC =*/1152921504606912513u, |
| /*GOLDFISH_DEVICE_LOCAL =*/1152921504606978048u, |
| /*GOLDFISH_HOST_VISIBLE =*/1152921504606978049u, |
| /*FRAMEBUFFER =*/1152921504607043585u, |
| }; |
| uint32_t index; |
| random(&index); |
| index %= std::size(valid); |
| *field = static_cast<v1::HeapType>(valid[index]); |
| } |
| |
| // If this ever stops being true, we can implement random<v1::wire::HeapType> by calling |
| // random<v1::HeapType>. |
| static_assert(std::is_same_v<v1::wire::HeapType, v1::HeapType>); |
| |
| template <> |
| void random<v1::PixelFormatType>(v1::PixelFormatType* field) { |
| // TODO(https://fxbug.dev/42130439): Use generated-code array of valid values instead, when/if |
| // available. |
| static constexpr uint32_t valid[] = { |
| /*INVALID =*/0u, |
| /*R8G8B8A8 =*/1u, |
| /*BGRA32 =*/101u, |
| /*I420 =*/102u, |
| /*M420 =*/103u, |
| /*NV12 =*/104u, |
| /*YUY2 =*/105u, |
| /*MJPEG =*/106u, |
| /*YV12 =*/107u, |
| /*BGR24 =*/108u, |
| /*RGB565 =*/109u, |
| /*RGB332 =*/110u, |
| /*RGB2220 =*/111u, |
| /*L8 =*/112u, |
| /*R8 =*/113u, |
| /*R8G8 =*/114u, |
| /*A2R10G10B10 =*/115u, |
| /*A2B10G10R10 =*/116u, |
| /*DO_NOT_CARE =*/0xFFFFFFFEu, |
| }; |
| uint32_t index; |
| random(&index); |
| index %= std::size(valid); |
| *field = static_cast<v1::PixelFormatType>(valid[index]); |
| } |
| |
| // If this ever stops being true, we can implement random<v1::wire::PixelFormatType> by calling |
| // random<v1::PixelFormatType>. |
| static_assert(std::is_same_v<v1::wire::PixelFormatType, v1::PixelFormatType>); |
| |
| template <> |
| void random<v1::ColorSpaceType>(v1::ColorSpaceType* field) { |
| // TODO(https://fxbug.dev/42130439): Use generated-code array of valid values instead, when/if |
| // available. |
| static constexpr uint32_t valid[] = { |
| /*INVALID =*/0u, |
| /*SRGB =*/1u, |
| /*REC601_NTSC =*/2u, |
| /*REC601_NTSC_FULL_RANGE =*/3u, |
| /*REC601_PAL =*/4u, |
| /*REC601_PAL_FULL_RANGE =*/5u, |
| /*REC709 =*/6u, |
| /*REC2020 =*/7u, |
| /*REC2100 =*/8u, |
| }; |
| uint32_t index; |
| random(&index); |
| index %= std::size(valid); |
| *field = static_cast<v1::ColorSpaceType>(valid[index]); |
| } |
| |
| // If this ever stops being true, we can implement random<v1::wire::ColorSpaceType> by calling |
| // random<v1::ColorSpaceType>. |
| static_assert(std::is_same_v<v1::wire::ColorSpaceType, v1::ColorSpaceType>); |
| |
| template <> |
| void random<v1::CoherencyDomain>(v1::CoherencyDomain* field) { |
| // TODO(https://fxbug.dev/42130439): Use generated-code array of valid values instead, when/if |
| // available. |
| static constexpr uint32_t valid[] = { |
| /*CPU =*/0u, |
| /*RAM =*/1u, |
| /*INACCESSIBLE =*/2u, |
| }; |
| uint32_t index; |
| random(&index); |
| index %= std::size(valid); |
| *field = static_cast<v1::CoherencyDomain>(valid[index]); |
| } |
| |
| // If this ever stops being true, we can implement random<v1::wire::CoherencyDomain> by calling |
| // random<v1::CoherencyDomain>. |
| static_assert(std::is_same_v<v1::wire::CoherencyDomain, v1::CoherencyDomain>); |
| |
| v1::BufferUsage V1RandomBufferUsage() { |
| v1::BufferUsage r{}; |
| random(&r.none()); |
| random(&r.cpu()); |
| random(&r.vulkan()); |
| random(&r.display()); |
| random(&r.video()); |
| return r; |
| } |
| |
| v1::wire::BufferUsage V1WireRandomBufferUsage() { |
| v1::wire::BufferUsage r{}; |
| random(&r.none); |
| random(&r.cpu); |
| random(&r.vulkan); |
| random(&r.display); |
| random(&r.video); |
| return r; |
| } |
| |
| v1::BufferMemoryConstraints V1RandomBufferMemoryConstraints() { |
| v1::BufferMemoryConstraints r{}; |
| random(&r.min_size_bytes()); |
| random(&r.max_size_bytes()); |
| random(&r.physically_contiguous_required()); |
| random(&r.secure_required()); |
| random(&r.ram_domain_supported()); |
| random(&r.cpu_domain_supported()); |
| random(&r.inaccessible_domain_supported()); |
| random(&r.heap_permitted_count()); |
| r.heap_permitted_count() %= fuchsia_sysmem::kMaxCountBufferMemoryConstraintsHeapPermitted; |
| for (uint32_t i = 0; i < r.heap_permitted_count(); ++i) { |
| random(&r.heap_permitted()[i]); |
| } |
| return r; |
| } |
| |
| v1::wire::BufferMemoryConstraints V1WireRandomBufferMemoryConstraints() { |
| v1::wire::BufferMemoryConstraints r{}; |
| random(&r.min_size_bytes); |
| random(&r.max_size_bytes); |
| random(&r.physically_contiguous_required); |
| random(&r.secure_required); |
| random(&r.ram_domain_supported); |
| random(&r.cpu_domain_supported); |
| random(&r.inaccessible_domain_supported); |
| random(&r.heap_permitted_count); |
| r.heap_permitted_count %= fuchsia_sysmem::wire::kMaxCountBufferMemoryConstraintsHeapPermitted; |
| for (uint32_t i = 0; i < r.heap_permitted_count; ++i) { |
| random(&r.heap_permitted[i]); |
| } |
| return r; |
| } |
| |
| v1::PixelFormat V1RandomPixelFormat() { |
| v1::PixelFormat r{}; |
| random(&r.type()); |
| random(&r.has_format_modifier()); |
| if (r.has_format_modifier()) { |
| random(&r.format_modifier().value()); |
| } |
| return r; |
| } |
| |
| v1::wire::PixelFormat V1WireRandomPixelFormat() { |
| v1::wire::PixelFormat r{}; |
| random(&r.type); |
| random(&r.has_format_modifier); |
| if (r.has_format_modifier) { |
| random(&r.format_modifier.value); |
| } |
| return r; |
| } |
| |
| v1::PixelFormatType V1RandomPixelFormatType() { |
| v1::PixelFormatType r{}; |
| random(&r); |
| return r; |
| } |
| |
| v1::ColorSpace V1RandomColorSpace() { |
| v1::ColorSpace r{}; |
| random(&r.type()); |
| return r; |
| } |
| |
| v1::wire::ColorSpace V1WireRandomColorSpace() { |
| v1::wire::ColorSpace r{}; |
| random(&r.type); |
| return r; |
| } |
| |
| v1::ImageFormatConstraints V1RandomImageFormatConstraints() { |
| v1::ImageFormatConstraints r{}; |
| r.pixel_format() = V1RandomPixelFormat(); |
| random(&r.color_spaces_count()); |
| r.color_spaces_count() %= fuchsia_sysmem::kMaxCountImageFormatConstraintsColorSpaces; |
| for (uint32_t i = 0; i < r.color_spaces_count(); ++i) { |
| r.color_space()[i] = V1RandomColorSpace(); |
| } |
| random(&r.min_coded_width()); |
| random(&r.max_coded_width()); |
| random(&r.min_coded_height()); |
| random(&r.max_coded_height()); |
| random(&r.min_bytes_per_row()); |
| random(&r.max_bytes_per_row()); |
| random(&r.max_coded_width_times_coded_height()); |
| // Both 0 and 1 are accepted by conversion code - but only 1 allows the value to be equal after |
| // round trip, so just use that. |
| r.layers() = 1; |
| random(&r.coded_width_divisor()); |
| random(&r.coded_height_divisor()); |
| random(&r.bytes_per_row_divisor()); |
| random(&r.start_offset_divisor()); |
| random(&r.display_width_divisor()); |
| random(&r.display_height_divisor()); |
| random(&r.required_min_coded_width()); |
| random(&r.required_max_coded_width()); |
| random(&r.required_min_coded_height()); |
| random(&r.required_max_coded_height()); |
| |
| // V2 does not have required_min_bytes_per_row, required_max_bytes_per_row, so we leave those zero |
| // here. |
| ZX_DEBUG_ASSERT(r.required_min_bytes_per_row() == 0); |
| ZX_DEBUG_ASSERT(r.required_max_bytes_per_row() == 0); |
| |
| return r; |
| } |
| |
| v1::wire::ImageFormatConstraints V1WireRandomImageFormatConstraints() { |
| v1::wire::ImageFormatConstraints r{}; |
| r.pixel_format = V1WireRandomPixelFormat(); |
| random(&r.color_spaces_count); |
| r.color_spaces_count %= fuchsia_sysmem::wire::kMaxCountImageFormatConstraintsColorSpaces; |
| for (uint32_t i = 0; i < r.color_spaces_count; ++i) { |
| r.color_space[i] = V1WireRandomColorSpace(); |
| } |
| random(&r.min_coded_width); |
| random(&r.max_coded_width); |
| random(&r.min_coded_height); |
| random(&r.max_coded_height); |
| random(&r.min_bytes_per_row); |
| random(&r.max_bytes_per_row); |
| random(&r.max_coded_width_times_coded_height); |
| // Both 0 and 1 are accepted by conversion code - but only 1 allows the value to be equal after |
| // round trip, so just use that. |
| r.layers = 1; |
| random(&r.coded_width_divisor); |
| random(&r.coded_height_divisor); |
| random(&r.bytes_per_row_divisor); |
| random(&r.start_offset_divisor); |
| random(&r.display_width_divisor); |
| random(&r.display_height_divisor); |
| random(&r.required_min_coded_width); |
| random(&r.required_max_coded_width); |
| random(&r.required_min_coded_height); |
| random(&r.required_max_coded_height); |
| |
| // V2 does not have required_min_bytes_per_row, required_max_bytes_per_row, so we leave those zero |
| // here. |
| ZX_DEBUG_ASSERT(r.required_min_bytes_per_row == 0); |
| ZX_DEBUG_ASSERT(r.required_max_bytes_per_row == 0); |
| |
| return r; |
| } |
| |
| v1::ImageFormat2 V1RandomImageFormat() { |
| v1::ImageFormat2 r{}; |
| r.pixel_format() = V1RandomPixelFormat(); |
| random(&r.coded_width()); |
| random(&r.coded_height()); |
| random(&r.bytes_per_row()); |
| random(&r.display_width()); |
| random(&r.display_height()); |
| // By design, the only value that'll round-trip is 1, so just use 1 here. |
| r.layers() = 1; |
| r.color_space() = V1RandomColorSpace(); |
| random(&r.has_pixel_aspect_ratio()); |
| if (r.has_pixel_aspect_ratio()) { |
| random(&r.pixel_aspect_ratio_width()); |
| random(&r.pixel_aspect_ratio_height()); |
| } |
| return r; |
| } |
| |
| v1::wire::ImageFormat2 V1WireRandomImageFormat() { |
| v1::wire::ImageFormat2 r{}; |
| r.pixel_format = V1WireRandomPixelFormat(); |
| random(&r.coded_width); |
| random(&r.coded_height); |
| random(&r.bytes_per_row); |
| random(&r.display_width); |
| random(&r.display_height); |
| // By design, the only value that'll round-trip is 1, so just use 1 here. |
| r.layers = 1; |
| r.color_space = V1WireRandomColorSpace(); |
| random(&r.has_pixel_aspect_ratio); |
| if (r.has_pixel_aspect_ratio) { |
| random(&r.pixel_aspect_ratio_width); |
| random(&r.pixel_aspect_ratio_height); |
| } |
| return r; |
| } |
| |
| v1::BufferMemorySettings V1RandomBufferMemorySettings() { |
| v1::BufferMemorySettings r{}; |
| random(&r.size_bytes()); |
| random(&r.is_physically_contiguous()); |
| random(&r.is_secure()); |
| random(&r.coherency_domain()); |
| random(&r.heap()); |
| return r; |
| } |
| |
| v1::wire::BufferMemorySettings V1WireRandomBufferMemorySettings() { |
| v1::wire::BufferMemorySettings r{}; |
| random(&r.size_bytes); |
| random(&r.is_physically_contiguous); |
| random(&r.is_secure); |
| random(&r.coherency_domain); |
| random(&r.heap); |
| return r; |
| } |
| |
| v1::SingleBufferSettings V1RandomSingleBufferSettings() { |
| v1::SingleBufferSettings r{}; |
| r.buffer_settings() = V1RandomBufferMemorySettings(); |
| random(&r.has_image_format_constraints()); |
| if (r.has_image_format_constraints()) { |
| r.image_format_constraints() = V1RandomImageFormatConstraints(); |
| } |
| return r; |
| } |
| |
| v1::wire::SingleBufferSettings V1WireRandomSingleBufferSettings() { |
| v1::wire::SingleBufferSettings r{}; |
| r.buffer_settings = V1WireRandomBufferMemorySettings(); |
| random(&r.has_image_format_constraints); |
| if (r.has_image_format_constraints) { |
| r.image_format_constraints = V1WireRandomImageFormatConstraints(); |
| } |
| return r; |
| } |
| |
| v1::VmoBuffer V1RandomVmoBuffer() { |
| v1::VmoBuffer r{}; |
| // Arbitrary is good enough - we don't need truly "random" for this. |
| zx::vmo arbitrary_vmo; |
| ZX_ASSERT(ZX_OK == zx::vmo::create(ZX_PAGE_SIZE, 0, &arbitrary_vmo)); |
| r.vmo() = std::move(arbitrary_vmo); |
| random(&r.vmo_usable_start()); |
| return r; |
| } |
| |
| v2::VmoBuffer V2RandomVmoBuffer() { |
| v2::VmoBuffer r{}; |
| |
| bool vmo_present; |
| random(&vmo_present); |
| if (vmo_present) { |
| // Arbitrary is good enough - we don't need truly "random" for this. |
| zx::vmo arbitrary_vmo; |
| ZX_ASSERT(ZX_OK == zx::vmo::create(ZX_PAGE_SIZE, 0, &arbitrary_vmo)); |
| r.vmo() = std::move(arbitrary_vmo); |
| } |
| |
| bool vmo_usable_start_present; |
| random(&vmo_usable_start_present); |
| if (vmo_usable_start_present) { |
| r.vmo_usable_start().emplace(0); |
| random(&r.vmo_usable_start().value()); |
| } |
| |
| bool close_weak_asap_present; |
| random(&close_weak_asap_present); |
| if (close_weak_asap_present) { |
| zx::eventpair event_pair_0; |
| zx::eventpair event_pair_1; |
| ZX_ASSERT(ZX_OK == zx::eventpair::create(0, &event_pair_0, &event_pair_1)); |
| r.close_weak_asap() = std::move(event_pair_0); |
| } |
| |
| return r; |
| } |
| |
| v1::wire::VmoBuffer V1WireRandomVmoBuffer() { |
| v1::wire::VmoBuffer r{}; |
| // Arbitrary is good enough - we don't need truly "random" for this. |
| zx::vmo arbitrary_vmo; |
| ZX_ASSERT(ZX_OK == zx::vmo::create(ZX_PAGE_SIZE, 0, &arbitrary_vmo)); |
| r.vmo = std::move(arbitrary_vmo); |
| random(&r.vmo_usable_start); |
| return r; |
| } |
| |
| v1::BufferCollectionInfo2 V1RandomBufferCollectionInfo() { |
| v1::BufferCollectionInfo2 r{}; |
| random(&r.buffer_count()); |
| r.buffer_count() %= v1::wire::kMaxCountBufferCollectionInfoBuffers; |
| r.settings() = V1RandomSingleBufferSettings(); |
| for (uint32_t i = 0; i < r.buffer_count(); ++i) { |
| r.buffers()[i] = V1RandomVmoBuffer(); |
| } |
| return r; |
| } |
| |
| v1::wire::BufferCollectionInfo2 V1WireRandomBufferCollectionInfo() { |
| v1::wire::BufferCollectionInfo2 r{}; |
| random(&r.buffer_count); |
| r.buffer_count %= v1::wire::kMaxCountBufferCollectionInfoBuffers; |
| r.settings = V1WireRandomSingleBufferSettings(); |
| for (uint32_t i = 0; i < r.buffer_count; ++i) { |
| r.buffers[i] = V1WireRandomVmoBuffer(); |
| } |
| return r; |
| } |
| |
| v1::BufferCollectionConstraints V1RandomBufferCollectionConstraints() { |
| v1::BufferCollectionConstraints r{}; |
| r.usage() = V1RandomBufferUsage(); |
| random(&r.min_buffer_count_for_camping()); |
| random(&r.min_buffer_count_for_dedicated_slack()); |
| random(&r.min_buffer_count_for_shared_slack()); |
| random(&r.min_buffer_count()); |
| random(&r.max_buffer_count()); |
| random(&r.has_buffer_memory_constraints()); |
| if (r.has_buffer_memory_constraints()) { |
| r.buffer_memory_constraints() = V1RandomBufferMemoryConstraints(); |
| } |
| random(&r.image_format_constraints_count()); |
| r.image_format_constraints_count() %= |
| fuchsia_sysmem::kMaxCountBufferCollectionConstraintsImageFormatConstraints; |
| for (uint32_t i = 0; i < r.image_format_constraints_count(); ++i) { |
| r.image_format_constraints()[i] = V1RandomImageFormatConstraints(); |
| } |
| return r; |
| } |
| |
| v1::wire::BufferCollectionConstraints V1WireRandomBufferCollectionConstraints() { |
| v1::wire::BufferCollectionConstraints r{}; |
| r.usage = V1WireRandomBufferUsage(); |
| random(&r.min_buffer_count_for_camping); |
| random(&r.min_buffer_count_for_dedicated_slack); |
| random(&r.min_buffer_count_for_shared_slack); |
| random(&r.min_buffer_count); |
| random(&r.max_buffer_count); |
| random(&r.has_buffer_memory_constraints); |
| if (r.has_buffer_memory_constraints) { |
| r.buffer_memory_constraints = V1WireRandomBufferMemoryConstraints(); |
| } |
| random(&r.image_format_constraints_count); |
| r.image_format_constraints_count %= |
| fuchsia_sysmem::wire::kMaxCountBufferCollectionConstraintsImageFormatConstraints; |
| for (uint32_t i = 0; i < r.image_format_constraints_count; ++i) { |
| r.image_format_constraints[i] = V1WireRandomImageFormatConstraints(); |
| } |
| return r; |
| } |
| |
| } // namespace |
| |
| TEST(SysmemVersion, EncodedEquality) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_buffer_usage = V1RandomBufferUsage(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_buffer_usage)); |
| auto snap_2 = SnapMoveFrom(std::move(snap_1->value())); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, EncodedEqualityWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_buffer_usage = V1WireRandomBufferUsage(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_buffer_usage)); |
| auto snap_2 = SnapMoveFrom(std::move(snap_1->value())); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferUsage) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomBufferUsage(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2 = sysmem::V2CopyFromV1BufferUsage(snap_1->value()).take_value(); |
| auto v1_2 = sysmem::V1CopyFromV2BufferUsage(v2); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferUsageWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomBufferUsage(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1BufferUsage(allocator, snap_1->value()).take_value(); |
| auto v2_2 = sysmem::V2CloneBufferUsage(allocator, v2_1); |
| auto v1_2 = sysmem::V1CopyFromV2BufferUsage(v2_2); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, PixelFormat) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomPixelFormat(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1PixelFormat(snap_1->value()); |
| // clone |
| auto v2_2 = v2_1; |
| auto v1_2 = sysmem::V1CopyFromV2PixelFormat(v2_2); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, PixelFormatType) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomPixelFormatType(); |
| auto v2_1 = sysmem::V2CopyFromV1PixelFormatType(v1_1); |
| auto v1_2 = sysmem::V1CopyFromV2PixelFormatType(v2_1); |
| EXPECT_EQ(v1_1, v1_2); |
| } |
| } |
| |
| TEST(SysmemVersion, PixelFormatWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomPixelFormat(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1PixelFormat(snap_1->value()); |
| // struct copy |
| auto v2_2 = v2_1; |
| auto v1_2 = sysmem::V1WireCopyFromV2PixelFormat(v2_2); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, ColorSpace) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomColorSpace(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1ColorSpace(snap_1->value()); |
| // clone |
| auto v2_2 = v2_1; |
| auto v1_2 = sysmem::V1CopyFromV2ColorSpace(v2_2); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, ColorSpaceWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomColorSpace(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1ColorSpace(snap_1->value()); |
| auto v2_2 = v2_1; |
| auto v1_2 = sysmem::V1WireCopyFromV2ColorSpace(v2_2); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, ImageFormatConstraints) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomImageFormatConstraints(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1ImageFormatConstraints(snap_1->value()).take_value(); |
| // clone |
| auto v2_2 = v2_1; |
| auto v1_2_result = sysmem::V1CopyFromV2ImageFormatConstraints(v2_2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, ImageFormatConstraintsWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomImageFormatConstraints(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1ImageFormatConstraints(allocator, snap_1->value()).take_value(); |
| auto v2_2 = sysmem::V2CloneImageFormatConstraints(allocator, v2_1); |
| auto v1_2_result = sysmem::V1CopyFromV2ImageFormatConstraints(v2_2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferMemoryConstraints) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomBufferMemoryConstraints(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1BufferMemoryConstraints(snap_1->value()).take_value(); |
| // clone |
| auto v2_2 = v2_1; |
| auto v1_2_result = sysmem::V1CopyFromV2BufferMemoryConstraints(v2_2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferMemoryConstraintsWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomBufferMemoryConstraints(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = |
| sysmem::V2CopyFromV1BufferMemoryConstraints(allocator, snap_1->value()).take_value(); |
| auto v2_2 = sysmem::V2CloneBufferMemoryConstraints(allocator, v2_1); |
| auto v1_2_result = sysmem::V1CopyFromV2BufferMemoryConstraints(v2_2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, ImageFormat) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomImageFormat(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1ImageFormat(snap_1->value()).take_value(); |
| auto v2_2 = v2_1; |
| auto v1_2_result = sysmem::V1CopyFromV2ImageFormat(v2_2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, ImageFormatWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomImageFormat(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2 = sysmem::V2CopyFromV1ImageFormat(allocator, snap_1->value()).take_value(); |
| // No V2CloneImageFormat(), so far. |
| auto v1_2_result = sysmem::V1CopyFromV2ImageFormat(v2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, ImageFormatNonZeroDisplayRectOriginFails) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomImageFormat(); |
| auto v2 = sysmem::V2CopyFromV1ImageFormat(v1_1).value(); |
| ASSERT_EQ(v2.display_rect()->x(), 0); |
| ASSERT_EQ(v2.display_rect()->y(), 0); |
| switch (run % 3) { |
| case 0: |
| // leave 0 |
| break; |
| case 1: |
| v2.display_rect()->x() = 1; |
| break; |
| case 2: |
| v2.display_rect()->y() = 1; |
| break; |
| } |
| auto v1_2_result = sysmem::V1CopyFromV2ImageFormat(v2); |
| switch (run % 3) { |
| case 0: |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| break; |
| case 1: |
| // fallthrough |
| case 2: |
| EXPECT_TRUE(v1_2_result.is_error()); |
| break; |
| } |
| } |
| } |
| |
| TEST(SysmemVersion, BufferMemorySettings) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomBufferMemorySettings(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1BufferMemorySettings(snap_1->value()); |
| // clone |
| auto v2_2 = v2_1; |
| auto v1_2_result = sysmem::V1CopyFromV2BufferMemorySettings(v2_2); |
| ASSERT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = std::move(v1_2_result.value()); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferMemorySettingsWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomBufferMemorySettings(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2CopyFromV1BufferMemorySettings(allocator, snap_1->value()); |
| auto v2_2 = sysmem::V2CloneBufferMemorySettings(allocator, v2_1); |
| auto v1_2_result = sysmem::V1CopyFromV2BufferMemorySettings(v2_2); |
| ASSERT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = std::move(v1_2_result.value()); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, SingleBufferSettings) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomSingleBufferSettings(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1_result = sysmem::V2CopyFromV1SingleBufferSettings(snap_1->value()); |
| EXPECT_TRUE(v2_1_result.is_ok()); |
| auto v2_1 = v2_1_result.take_value(); |
| auto v2_2 = v2_1; |
| auto v1_2_result = sysmem::V1CopyFromV2SingleBufferSettings(v2_2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| |
| auto v2_builder_result = sysmem::V2CopyFromV1SingleBufferSettings(snap_1->value()); |
| EXPECT_TRUE(v2_builder_result.is_ok()); |
| auto v2_3 = v2_builder_result.value(); |
| auto v1_3_result = sysmem::V1CopyFromV2SingleBufferSettings(v2_3); |
| EXPECT_TRUE(v1_3_result.is_ok()); |
| auto v1_3 = v1_3_result.take_value(); |
| auto snap_3 = SnapMoveFrom(std::move(v1_3)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_3)); |
| } |
| } |
| |
| TEST(SysmemVersion, SingleBufferSettingsWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomSingleBufferSettings(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1_result = sysmem::V2CopyFromV1SingleBufferSettings(allocator, snap_1->value()); |
| EXPECT_TRUE(v2_1_result.is_ok()); |
| auto v2_1 = v2_1_result.take_value(); |
| auto v2_2 = sysmem::V2CloneSingleBufferSettings(allocator, v2_1); |
| auto v1_2_result = sysmem::V1CopyFromV2SingleBufferSettings(v2_2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| |
| auto v2_builder_result = sysmem::V2CopyFromV1SingleBufferSettings(allocator, snap_1->value()); |
| EXPECT_TRUE(v2_builder_result.is_ok()); |
| auto v2_3 = sysmem::V2CloneSingleBufferSettings(allocator, v2_builder_result.value()); |
| auto v1_3_result = sysmem::V1CopyFromV2SingleBufferSettings(v2_3); |
| EXPECT_TRUE(v1_3_result.is_ok()); |
| auto v1_3 = v1_3_result.take_value(); |
| auto snap_3 = SnapMoveFrom(std::move(v1_3)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_3)); |
| } |
| } |
| |
| TEST(SysmemVersion, VmoBuffer) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomVmoBuffer(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2MoveFromV1VmoBuffer(std::move(snap_1->value())); |
| auto v2_2_result = sysmem::V2CloneVmoBuffer(v2_1, std::numeric_limits<uint32_t>::max()); |
| EXPECT_TRUE(v2_2_result.is_ok()); |
| auto v2_2 = v2_2_result.take_value(); |
| auto v1_2 = sysmem::V1MoveFromV2VmoBuffer(std::move(v2_1)); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| auto v1_3 = sysmem::V1MoveFromV2VmoBuffer(std::move(v2_2)); |
| auto snap_3 = SnapMoveFrom(std::move(v1_3)); |
| EXPECT_FALSE(IsEqual(*snap_1, *snap_3)); |
| EXPECT_TRUE(IsEqualByKoid(*snap_1, *snap_3)); |
| EXPECT_TRUE(IsEqualByKoid(*snap_2, *snap_3)); |
| } |
| } |
| |
| TEST(SysmemVersion, VmoBufferV2) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v2_1 = V2RandomVmoBuffer(); |
| auto v2_2_result = sysmem::V2CloneVmoBuffer(v2_1, std::numeric_limits<uint32_t>::max()); |
| ASSERT_TRUE(v2_2_result.is_ok()); |
| auto snap_1 = SnapMoveFrom(std::move(v2_1)); |
| auto v2_2 = v2_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v2_2)); |
| EXPECT_FALSE(IsEqual(*snap_1, *snap_2)); |
| EXPECT_TRUE(IsEqualByKoid(*snap_1, *snap_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, VmoBufferWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomVmoBuffer(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1 = sysmem::V2MoveFromV1VmoBuffer(allocator, std::move(snap_1->value())); |
| auto v2_2_result = |
| sysmem::V2CloneVmoBuffer(allocator, v2_1, std::numeric_limits<uint32_t>::max()); |
| EXPECT_TRUE(v2_2_result.is_ok()); |
| auto v2_2 = v2_2_result.take_value(); |
| auto v1_2 = sysmem::V1MoveFromV2VmoBuffer(std::move(v2_1)); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| auto v1_3 = sysmem::V1MoveFromV2VmoBuffer(std::move(v2_2)); |
| auto snap_3 = SnapMoveFrom(std::move(v1_3)); |
| EXPECT_FALSE(IsEqual(*snap_1, *snap_3)); |
| EXPECT_TRUE(IsEqualByKoid(*snap_1, *snap_3)); |
| EXPECT_TRUE(IsEqualByKoid(*snap_2, *snap_3)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferCollectionInfo) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomBufferCollectionInfo(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1_result = sysmem::V2MoveFromV1BufferCollectionInfo(std::move(snap_1->value())); |
| EXPECT_TRUE(v2_1_result.is_ok()); |
| auto v2_1 = v2_1_result.take_value(); |
| auto v2_2_result = |
| sysmem::V2CloneBufferCollectionInfo(v2_1, std::numeric_limits<uint32_t>::max()); |
| EXPECT_TRUE(v2_2_result.is_ok()); |
| auto v2_2 = v2_2_result.take_value(); |
| auto v1_2_result = sysmem::V1MoveFromV2BufferCollectionInfo(std::move(v2_1)); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| auto v1_3_result = sysmem::V1MoveFromV2BufferCollectionInfo(std::move(v2_2)); |
| EXPECT_TRUE(v1_3_result.is_ok()); |
| auto v1_3 = v1_3_result.take_value(); |
| auto snap_3 = SnapMoveFrom(std::move(v1_3)); |
| EXPECT_TRUE(!IsEqual(*snap_1, *snap_3) || snap_3->value().buffer_count() == 0); |
| EXPECT_TRUE(IsEqualByKoid(*snap_1, *snap_3)); |
| EXPECT_TRUE(IsEqualByKoid(*snap_2, *snap_3)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferCollectionInfoWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomBufferCollectionInfo(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| auto v2_1_result = |
| sysmem::V2MoveFromV1BufferCollectionInfo(allocator, std::move(snap_1->value())); |
| EXPECT_TRUE(v2_1_result.is_ok()); |
| auto v2_1 = v2_1_result.take_value(); |
| auto v2_2_result = |
| sysmem::V2CloneBufferCollectionInfo(allocator, v2_1, std::numeric_limits<uint32_t>::max()); |
| EXPECT_TRUE(v2_2_result.is_ok()); |
| auto v2_2 = v2_2_result.take_value(); |
| auto v1_2_result = sysmem::V1MoveFromV2BufferCollectionInfo(std::move(v2_1)); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.take_value(); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| auto v1_3_result = sysmem::V1MoveFromV2BufferCollectionInfo(std::move(v2_2)); |
| EXPECT_TRUE(v1_3_result.is_ok()); |
| auto v1_3 = v1_3_result.take_value(); |
| auto snap_3 = SnapMoveFrom(std::move(v1_3)); |
| EXPECT_TRUE(!IsEqual(*snap_1, *snap_3) || snap_3->value().buffer_count == 0); |
| EXPECT_TRUE(IsEqualByKoid(*snap_1, *snap_3)); |
| EXPECT_TRUE(IsEqualByKoid(*snap_2, *snap_3)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferCollectionConstraints) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| auto v1_1 = V1RandomBufferCollectionConstraints(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| bool has_main; |
| random(&has_main); |
| v1::BufferCollectionConstraints* maybe_main = has_main ? &snap_1->value() : nullptr; |
| auto v2 = sysmem::V2CopyFromV1BufferCollectionConstraints(maybe_main).take_value(); |
| auto v2_clone = v2; |
| auto v1_2_result = sysmem::V1CopyFromV2BufferCollectionConstraints(v2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2_optional = v1_2_result.take_value(); |
| |
| auto v2_snap = SnapMoveFrom(std::move(v2)); |
| auto v2_clone_snap = SnapMoveFrom(std::move(v2_clone)); |
| EXPECT_TRUE(IsEqual(*v2_snap, *v2_clone_snap)); |
| |
| if (has_main) { |
| EXPECT_TRUE(!!v1_2_optional); |
| auto v1_2 = std::move(v1_2_optional.value()); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } else { |
| auto v1_2 = v1::BufferCollectionConstraints{}; |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| |
| auto v2_2 = v2; |
| auto snap_v2 = SnapMoveFrom(std::move(v2)); |
| auto snap_v2_2 = SnapMoveFrom(std::move(v2_2)); |
| EXPECT_TRUE(IsEqual(*snap_v2, *snap_v2_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, BufferCollectionConstraintsWire) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fidl::Arena allocator; |
| auto v1_1 = V1WireRandomBufferCollectionConstraints(); |
| auto snap_1 = SnapMoveFrom(std::move(v1_1)); |
| bool has_main; |
| random(&has_main); |
| v1::wire::BufferCollectionConstraints* maybe_main = has_main ? &snap_1->value() : nullptr; |
| auto v2 = sysmem::V2CopyFromV1BufferCollectionConstraints(allocator, maybe_main).take_value(); |
| auto v2_clone = sysmem::V2CloneBufferCollectionConstraints(allocator, v2); |
| auto v1_2_result = sysmem::V1CopyFromV2BufferCollectionConstraints(v2); |
| EXPECT_TRUE(v1_2_result.is_ok()); |
| auto v1_2_optional = v1_2_result.take_value(); |
| |
| auto v2_snap = SnapMoveFrom(std::move(v2)); |
| auto v2_clone_snap = SnapMoveFrom(std::move(v2_clone)); |
| EXPECT_TRUE(IsEqual(*v2_snap, *v2_clone_snap)); |
| |
| if (has_main) { |
| EXPECT_TRUE(!!v1_2_optional); |
| auto v1_2 = std::move(v1_2_optional.value()); |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } else { |
| auto v1_2 = v1::wire::BufferCollectionConstraints{}; |
| auto snap_2 = SnapMoveFrom(std::move(v1_2)); |
| EXPECT_TRUE(IsEqual(*snap_1, *snap_2)); |
| } |
| |
| auto v2_2 = sysmem::V2CloneBufferCollectionConstraints(allocator, v2); |
| auto snap_v2 = SnapMoveFrom(std::move(v2)); |
| auto snap_v2_2 = SnapMoveFrom(std::move(v2_2)); |
| EXPECT_TRUE(IsEqual(*snap_v2, *snap_v2_2)); |
| } |
| } |
| |
| TEST(SysmemVersion, HeapType) { |
| for (uint32_t run = 0; run < kRunCount; ++run) { |
| fuchsia_sysmem::HeapType v1_1; |
| random(&v1_1); |
| auto v2_1_result = sysmem::V2CopyFromV1HeapType(v1_1); |
| ASSERT_TRUE(v2_1_result.is_ok()); |
| std::string heap_type_v2 = v2_1_result.value(); |
| auto v1_2_result = sysmem::V1CopyFromV2HeapType(heap_type_v2); |
| ASSERT_TRUE(v1_2_result.is_ok()); |
| auto v1_2 = v1_2_result.value(); |
| EXPECT_EQ(v1_1, v1_2); |
| } |
| } |
| |
| TEST(SysmemVersion, ErrorSpaceConversion) { |
| using Error = fuchsia_sysmem2::Error; |
| const std::pair<Error, zx_status_t> errors[] = { |
| {Error::kUnspecified, ZX_ERR_INTERNAL}, |
| {Error::kProtocolDeviation, ZX_ERR_INVALID_ARGS}, |
| {Error::kNotFound, ZX_ERR_NOT_FOUND}, |
| {Error::kHandleAccessDenied, ZX_ERR_ACCESS_DENIED}, |
| {Error::kNoMemory, ZX_ERR_NO_MEMORY}, |
| {Error::kConstraintsIntersectionEmpty, ZX_ERR_NOT_SUPPORTED}, |
| {Error::kPending, ZX_ERR_UNAVAILABLE}, |
| {Error::kTooManyGroupChildCombinations, ZX_ERR_OUT_OF_RANGE}, |
| }; |
| for (auto& pair : errors) { |
| zx_status_t zx_status = sysmem::V1CopyFromV2Error(pair.first); |
| EXPECT_EQ(pair.second, zx_status); |
| Error error = sysmem::V2CopyFromV1Error(pair.second); |
| EXPECT_EQ(pair.first, error); |
| } |
| } |