blob: 1b00a90d403e99067c64b3da1b72a722fac706b9 [file] [log] [blame]
// 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.
// This is separate from test_utils as it is not used in conformance tests and
// can therefore e.g. use handles
#ifndef SRC_LIB_FIDL_LLCPP_TESTS_TYPES_TEST_UTILS_H_
#define SRC_LIB_FIDL_LLCPP_TESTS_TYPES_TEST_UTILS_H_
#ifndef __Fuchsia__
#error "Fuchsia-only header"
#endif // __Fuchsia__
#include <lib/fidl/cpp/wire/message.h>
#include <lib/fidl/cpp/wire/traits.h>
#include <lib/zx/event.h>
#include <zircon/fidl.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <vector>
#include <gtest/gtest.h>
namespace llcpp_types_test_utils {
// HandleChecker checks all |zx::event| handles registered with it are freed.
class HandleChecker {
public:
HandleChecker() = default;
size_t size() const { return events_.size(); }
void AddEvent(zx_handle_t event);
void AddEvent(const zx::event& event);
// Tests expectations that all handles registered via |AddEvent| has been
// closed. Note that the kernel object is still kept alive by this class.
void CheckEvents();
private:
std::vector<zx::event> events_;
};
// Verifies that:
// - |bytes| and |handles| decodes successfully as |FidlType|
// - all handles in |handles| are closed
// - the resulting object fails to encode
//
// Requires that:
// - If FidlType is a transactional message wrapper, it must have a single
// `result` field that is either a union or a table.
// - Otherwise, FidlType should be a wire domain object.
//
// Also runs a checker function on the decoded object, to test any properties.
//
// This is the intended behavior for all flexible types (unions and tables) in
// LLCPP, regardless of resourceness (since no unknown handles are stored, even on
// resource types).
template <typename FidlType, typename CheckerFunc>
void CannotProxyUnknownEnvelope(std::vector<uint8_t> bytes, std::vector<zx_handle_t> handles,
CheckerFunc check) {
HandleChecker handle_checker;
for (const auto& handle : handles) {
handle_checker.AddEvent(handle);
}
std::vector<zx_handle_info_t> handle_infos;
for (zx_handle_t handle : handles) {
handle_infos.push_back({
.handle = handle,
.type = ZX_OBJ_TYPE_NONE,
.rights = ZX_RIGHT_SAME_RIGHTS,
});
}
const char* decode_error;
uint8_t* trimmed_bytes = bytes.data();
uint32_t trimmed_num_bytes = static_cast<uint32_t>(bytes.size());
if (fidl::IsFidlTransactionalMessage<FidlType>::value) {
zx_status_t status = ::fidl::internal::fidl_exclude_header_bytes(
trimmed_bytes, trimmed_num_bytes, &trimmed_bytes, &trimmed_num_bytes, &decode_error);
ASSERT_EQ(status, ZX_OK) << decode_error;
}
auto status = fidl_decode_etc(fidl::TypeTraits<FidlType>::kType, trimmed_bytes, trimmed_num_bytes,
handle_infos.data(), static_cast<uint32_t>(handle_infos.size()),
&decode_error);
ASSERT_EQ(status, ZX_OK) << decode_error;
auto result = reinterpret_cast<FidlType*>(&bytes[0]);
if constexpr (fidl::IsFidlTransactionalMessage<FidlType>::value) {
check(result->body.result);
} else {
check(*result);
}
handle_checker.CheckEvents();
// Here we want to encode a message with unknown data. To be able to encoded all the unknown data,
// we always use a full size buffer.
FIDL_ALIGNDECL
uint8_t encoded_bytes[ZX_CHANNEL_MAX_MSG_BYTES];
fidl::internal::UnownedEncodedMessage<FidlType> encoded(
fidl::internal::kLLCPPWireFormatVersion, encoded_bytes, ZX_CHANNEL_MAX_MSG_BYTES, result);
ASSERT_EQ(encoded.status(), ZX_ERR_INVALID_ARGS) << encoded.status_string();
// TODO(https://fxbug.dev/42110793): Test a reason enum instead of comparing strings.
EXPECT_EQ(std::string(encoded.lossy_description()), "unknown union tag") << encoded.error();
}
} // namespace llcpp_types_test_utils
#endif // SRC_LIB_FIDL_LLCPP_TESTS_TYPES_TEST_UTILS_H_