[llcpp] fidl::LinearizeAndEncode + passing conformance tests
Will switch over to LinearizeAndEncode in next CL.
Change Ia83987d7995066d9a82c8d347cd0f34cc6803b75 is needed for
this to work with empty requests / responses.
Change-Id: Ibe04b261d169039495ef28e2143c1e83b4282757
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/396713
Commit-Queue: Benjamin Prosnitz <bprosnitz@google.com>
Reviewed-by: Yifei Teng <yifeit@google.com>
Testability-Review: Yifei Teng <yifeit@google.com>
diff --git a/src/lib/fidl/llcpp/tests/test_utils.h b/src/lib/fidl/llcpp/tests/test_utils.h
index 9efd3ce..29a6778 100644
--- a/src/lib/fidl/llcpp/tests/test_utils.h
+++ b/src/lib/fidl/llcpp/tests/test_utils.h
@@ -5,7 +5,9 @@
#ifndef SRC_LIB_FIDL_LLCPP_TESTS_TEST_UTILS_H_
#define SRC_LIB_FIDL_LLCPP_TESTS_TEST_UTILS_H_
+#include <lib/fidl/llcpp/aligned.h>
#include <lib/fidl/llcpp/coding.h>
+#include <lib/fidl/llcpp/linearized.h>
#include <zircon/status.h>
#include <zircon/types.h>
@@ -14,56 +16,21 @@
#include <iostream>
#include <vector>
+// Testing utilities indended for GIDL-generated conformance tests.
namespace llcpp_conformance_utils {
bool ComparePayload(const uint8_t* actual, size_t actual_size, const uint8_t* expected,
size_t expected_size);
-// A wrapper around fidl::LinearizeResult that owns the memory.
-template <typename FidlType>
-struct OwnedLinearizeResult {
- // The result, whose message field points to either inline_buffer or
- // linearized_buffer (or neither in error conditions).
- fidl::LinearizeResult<FidlType> result;
- // Used for types with no out-of-line parts, which do not need linearization.
- FIDL_ALIGNDECL char inline_buffer[FidlAlign(sizeof(FidlType))];
- // Used in the general case where linearization is needed.
- std::vector<uint8_t> linearized_buffer;
-};
-
-// Linearizes |value|, producing an |OwnedLinearizeResult|.
-// Note: This is destructive to |value|.
-template <typename FidlType>
-OwnedLinearizeResult<FidlType> Linearize(FidlType* value) {
- static_assert(fidl::IsFidlType<FidlType>::value, "FIDL type required");
-
- OwnedLinearizeResult<FidlType> owned_result;
- FidlType* aligned_value = new (owned_result.inline_buffer) FidlType(std::move(*value));
-
- if constexpr (FidlType::HasPointer) {
- owned_result.linearized_buffer.resize(ZX_CHANNEL_MAX_MSG_BYTES);
- memset(owned_result.linearized_buffer.data(), 0xcd, owned_result.linearized_buffer.size());
- owned_result.result = fidl::Linearize(
- aligned_value,
- fidl::BytePart(&owned_result.linearized_buffer[0], ZX_CHANNEL_MAX_MSG_BYTES));
- } else {
- owned_result.result =
- fidl::LinearizeResult(ZX_OK, nullptr,
- fidl::DecodedMessage<FidlType>(fidl::BytePart(
- reinterpret_cast<uint8_t*>(aligned_value),
- FidlAlign(sizeof(FidlType)), FidlAlign(sizeof(FidlType)))));
- }
- return owned_result;
-}
-
// Verifies that |value| encodes to |bytes|.
-// Note: This is destructive to |value|.
+// Note: This is destructive to |value| - a new value must be created with each call.
template <typename FidlType>
-bool EncodeSuccess(FidlType* value, const std::vector<uint8_t>& bytes) {
+bool LinearizeThenEncodeSuccess(FidlType* value, const std::vector<uint8_t>& bytes) {
static_assert(fidl::IsFidlType<FidlType>::value, "FIDL type required");
- auto owned_linearize_result = Linearize(value);
- auto& linearize_result = owned_linearize_result.result;
+ fidl::aligned<FidlType> aligned_value = std::move(*value);
+ auto linearized = fidl::internal::Linearized<FidlType>(&aligned_value.value);
+ auto& linearize_result = linearized.result();
if (linearize_result.status != ZX_OK || linearize_result.error != nullptr) {
std::cout << "Linearization failed (" << zx_status_get_string(linearize_result.status)
<< "): " << linearize_result.error << std::endl;
@@ -81,13 +48,14 @@
}
// Verifies that |value| fails to encode, with the expected error code.
-// Note: This is destructive to |value|.
+// Note: This is destructive to |value| - a new value must be created with each call.
template <typename FidlType>
-bool EncodeFailure(FidlType* value, zx_status_t expected_error_code) {
+bool LinearizeThenEncodeFailure(FidlType* value, zx_status_t expected_error_code) {
static_assert(fidl::IsFidlType<FidlType>::value, "FIDL type required");
- auto owned_linearize_result = Linearize(value);
- auto& linearize_result = owned_linearize_result.result;
+ fidl::aligned<FidlType> aligned_value = std::move(*value);
+ auto linearized = fidl::internal::Linearized<FidlType>(&aligned_value.value);
+ auto& linearize_result = linearized.result();
if (linearize_result.status != ZX_OK && linearize_result.status != expected_error_code) {
std::cout << "Linearization failed with error code "
<< zx_status_get_string(linearize_result.status) << " (" << linearize_result.error
@@ -110,6 +78,44 @@
return true;
}
+// Verifies that |value| encodes to |bytes|.
+// Note: This is destructive to |value| - a new value must be created with each call.
+template <typename FidlType>
+bool CombinedLinearizeAndEncodeSuccess(FidlType* value, const std::vector<uint8_t>& bytes) {
+ static_assert(fidl::IsFidlType<FidlType>::value, "FIDL type required");
+
+ ::fidl::internal::LinearizeBuffer<FidlType> buffer;
+ auto encode_result = fidl::LinearizeAndEncode(value, buffer.buffer());
+ if (encode_result.status != ZX_OK || encode_result.error != nullptr) {
+ std::cout << "Encoding failed (" << zx_status_get_string(encode_result.status)
+ << "): " << encode_result.error << std::endl;
+ return false;
+ }
+ return ComparePayload(encode_result.message.bytes().data(),
+ encode_result.message.bytes().actual(), &bytes[0], bytes.size());
+}
+
+// Verifies that |value| fails to encode, with the expected error code.
+// Note: This is destructive to |value| - a new value must be created with each call.
+template <typename FidlType>
+bool CombinedLinearizeAndEncodeFailure(FidlType* value, zx_status_t expected_error_code) {
+ static_assert(fidl::IsFidlType<FidlType>::value, "FIDL type required");
+
+ ::fidl::internal::LinearizeBuffer<FidlType> buffer;
+ auto encode_result = fidl::LinearizeAndEncode(value, buffer.buffer());
+ if (encode_result.status == ZX_OK) {
+ std::cout << "Encoding unexpectedly succeeded" << std::endl;
+ return false;
+ }
+ if (encode_result.status != expected_error_code) {
+ std::cout << "Encoding failed with error code " << zx_status_get_string(encode_result.status)
+ << " (" << encode_result.error << "), but expected error code "
+ << zx_status_get_string(expected_error_code) << std::endl;
+ return false;
+ }
+ return true;
+}
+
// Verifies that |bytes| decodes to an object that is the same as |value|.
template <typename FidlType>
bool DecodeSuccess(FidlType* value, std::vector<uint8_t> bytes) {
diff --git a/tools/fidl/gidl/llcpp/conformance.go b/tools/fidl/gidl/llcpp/conformance.go
index 3636890..bcccca1 100644
--- a/tools/fidl/gidl/llcpp/conformance.go
+++ b/tools/fidl/gidl/llcpp/conformance.go
@@ -28,13 +28,21 @@
#include "src/lib/fidl/llcpp/tests/test_utils.h"
{{ range .EncodeSuccessCases }}
-TEST(Conformance, {{ .Name }}_Encode) {
+TEST(Conformance, {{ .Name }}_LinearizeThenEncode) {
fidl::UnsafeBufferAllocator<ZX_CHANNEL_MAX_MSG_BYTES> allocator;
fidl::Allocator* allocator_ptr __attribute__((unused)) = &allocator;
{{ .ValueBuild }}
const auto expected = {{ .Bytes }};
auto obj = {{ .ValueVar }};
- EXPECT_TRUE(llcpp_conformance_utils::EncodeSuccess(&obj, expected));
+ EXPECT_TRUE(llcpp_conformance_utils::LinearizeThenEncodeSuccess(&obj, expected));
+}
+TEST(Conformance, {{ .Name }}_CombinedLinearizeAndEncode) {
+ fidl::UnsafeBufferAllocator<ZX_CHANNEL_MAX_MSG_BYTES> allocator;
+ fidl::Allocator* allocator_ptr __attribute__((unused)) = &allocator;
+ {{ .ValueBuild }}
+ const auto expected = {{ .Bytes }};
+ auto obj = {{ .ValueVar }};
+ EXPECT_TRUE(llcpp_conformance_utils::CombinedLinearizeAndEncodeSuccess(&obj, expected));
}
{{ end }}
@@ -50,12 +58,19 @@
{{ end }}
{{ range .EncodeFailureCases }}
-TEST(Conformance, {{ .Name }}_Encode_Failure) {
+TEST(Conformance, {{ .Name }}_LinearizeThenEncode_Failure) {
fidl::UnsafeBufferAllocator<ZX_CHANNEL_MAX_MSG_BYTES> allocator;
fidl::Allocator* allocator_ptr __attribute__((unused)) = &allocator;
{{ .ValueBuild }}
auto obj = {{ .ValueVar }};
- EXPECT_TRUE(llcpp_conformance_utils::EncodeFailure(&obj, {{ .ErrorCode }}));
+ EXPECT_TRUE(llcpp_conformance_utils::LinearizeThenEncodeFailure(&obj, {{ .ErrorCode }}));
+}
+TEST(Conformance, {{ .Name }}_CombinedLinearizeAndEncode_Failure) {
+ fidl::UnsafeBufferAllocator<ZX_CHANNEL_MAX_MSG_BYTES> allocator;
+ fidl::Allocator* allocator_ptr __attribute__((unused)) = &allocator;
+ {{ .ValueBuild }}
+ auto obj = {{ .ValueVar }};
+ EXPECT_TRUE(llcpp_conformance_utils::CombinedLinearizeAndEncodeFailure(&obj, {{ .ErrorCode }}));
}
{{ end }}
diff --git a/zircon/system/ulib/fidl/include/lib/fidl/llcpp/coding.h b/zircon/system/ulib/fidl/include/lib/fidl/llcpp/coding.h
index 0106106..c831748 100644
--- a/zircon/system/ulib/fidl/include/lib/fidl/llcpp/coding.h
+++ b/zircon/system/ulib/fidl/include/lib/fidl/llcpp/coding.h
@@ -197,6 +197,26 @@
return result;
}
+template <typename FidlType>
+EncodeResult<FidlType> LinearizeAndEncode(FidlType* value, BytePart bytes) {
+ static_assert(IsFidlType<FidlType>::value, "FIDL type required");
+ static_assert(FidlType::Type != nullptr, "FidlType should have a coding table");
+ EncodeResult<FidlType> result;
+ uint32_t num_bytes_actual;
+ uint32_t num_handles_actual;
+ result.message.bytes() = std::move(bytes);
+ result.status = fidl_linearize_and_encode(
+ FidlType::Type, value, result.message.bytes().data(), result.message.bytes().capacity(),
+ result.message.handles().data(), result.message.handles().capacity(), &num_bytes_actual,
+ &num_handles_actual, &result.error);
+ if (result.status != ZX_OK) {
+ return result;
+ }
+ result.message.bytes().set_actual(num_bytes_actual);
+ result.message.handles().set_actual(num_handles_actual);
+ return result;
+}
+
#ifdef __Fuchsia__
namespace {