blob: e5543bd93056c8a89d1c51b1ca2c69cc181a7647 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "serializer_traits.h"
#include <array>
#include "serializable.h"
#include "test_platform.h"
// The purpose of this test is to ensure that the
// {Field}SerializerTraits<X>::Serialize methods invoke the appropriate
// functions from cbor.h; so, it's usually sufficient to compare with what
// cbor.h function invocations would produce, rather than making assertions on
// the specific bytes emitted by the SerializerTraits code.
namespace v8_crdtp {
namespace {
// =============================================================================
// SerializerTraits - Encodes field values of protocol objects in CBOR.
// =============================================================================
TEST(SerializerTraits, Bool) {
std::vector<uint8_t> out;
SerializerTraits<bool>::Serialize(true, &out);
SerializerTraits<bool>::Serialize(false, &out);
EXPECT_THAT(out,
testing::ElementsAre(cbor::EncodeTrue(), cbor::EncodeFalse()));
}
TEST(SerializerTraits, Double) {
std::vector<uint8_t> out;
SerializerTraits<double>::Serialize(1.00001, &out);
std::vector<uint8_t> expected;
cbor::EncodeDouble(1.00001, &expected);
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
TEST(SerializerTraits, Int32) {
std::vector<uint8_t> out;
SerializerTraits<int32_t>::Serialize(42, &out);
std::vector<uint8_t> expected;
cbor::EncodeInt32(42, &expected);
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
TEST(SerializerTraits, VectorOfInt32) {
std::vector<int32_t> ints = {1, 2, 3};
std::vector<uint8_t> out;
SerializerTraits<std::vector<int32_t>>::Serialize(ints, &out);
std::vector<uint8_t> expected;
expected.push_back(cbor::EncodeIndefiniteLengthArrayStart());
for (int32_t v : ints)
cbor::EncodeInt32(v, &expected);
expected.push_back(cbor::EncodeStop());
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
// Foo is an example for a domain specific type.
class Foo : public Serializable {
public:
Foo(int32_t value) : value(value) {}
int32_t value;
void AppendSerialized(std::vector<uint8_t>* out) const override {
// In production, this would be generated code which emits a
// CBOR map that has STRING8 keys corresponding to the field names
// and field values encoded using SerializerTraits::Serialize.
//
// For the test we simplify this drastically and just emit the field
// value, for conveniently testing std::vector<std::unique_ptr<Foo>>,
// as well as the convenience methods for raw pointer and unique_ptr.
SerializerTraits<int32_t>::Serialize(value, out);
}
};
TEST(SerializerTraits, VectorOfDomainSpecificType) {
std::vector<std::unique_ptr<Foo>> foos;
foos.push_back(std::make_unique<Foo>(1));
foos.push_back(std::make_unique<Foo>(2));
foos.push_back(std::make_unique<Foo>(3));
std::vector<uint8_t> out;
SerializerTraits<std::vector<std::unique_ptr<Foo>>>::Serialize(foos, &out);
std::vector<uint8_t> expected;
expected.push_back(cbor::EncodeIndefiniteLengthArrayStart());
for (int32_t v : {1, 2, 3})
cbor::EncodeInt32(v, &expected);
expected.push_back(cbor::EncodeStop());
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
TEST(SerializerTraits, ConstRefAndUniquePtr) {
// Shows that SerializerTraits<Foo> allows unique_ptr.
Foo foo(42);
auto bar = std::make_unique<Foo>(21);
std::vector<uint8_t> out;
// In this case, |foo| is taken as a const Foo&.
SerializerTraits<Foo>::Serialize(foo, &out);
// In this case, |bar| is taken as a const std::unique_ptr<Foo>&.
SerializerTraits<std::unique_ptr<Foo>>::Serialize(bar, &out);
std::vector<uint8_t> expected;
cbor::EncodeInt32(42, &expected);
cbor::EncodeInt32(21, &expected);
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
TEST(SerializerTraits, UTF8String) {
std::string msg = "Hello, 🌎.";
std::vector<uint8_t> out;
SerializerTraits<std::string>::Serialize(msg, &out);
std::vector<uint8_t> expected;
cbor::EncodeString8(SpanFrom(msg), &expected);
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
// A trivial model of Exported.
// (see
// https://cs.chromium.org/chromium/src/out/Debug/gen/v8/include/inspector/Debugger.h).
struct Exported {
std::string msg;
void AppendSerialized(std::vector<uint8_t>* out) const {
cbor::EncodeString8(SpanFrom(msg), out);
}
};
TEST(SerializerTraits, Exported) {
Exported exported;
exported.msg = "Hello, world.";
std::vector<uint8_t> out;
SerializerTraits<Exported>::Serialize(exported, &out);
std::vector<uint8_t> expected;
cbor::EncodeString8(SpanFrom(exported.msg), &expected);
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
// =============================================================================
// FieldSerializerTraits - Encodes fields of protocol objects in CBOR
// =============================================================================
TEST(FieldSerializerTraits, RequiredField) {
std::string value = "Hello, world.";
std::vector<uint8_t> out;
SerializeField(SpanFrom("msg"), value, &out);
std::vector<uint8_t> expected;
cbor::EncodeString8(SpanFrom("msg"), &expected);
cbor::EncodeString8(SpanFrom(value), &expected);
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
template <typename T>
class FieldSerializerTraits_MaybeTest : public ::testing::Test {};
using MaybeTypes =
::testing::Types<detail::ValueMaybe<bool>,
detail::ValueMaybe<double>,
detail::ValueMaybe<int32_t>,
detail::ValueMaybe<std::string>,
detail::PtrMaybe<Foo>,
detail::PtrMaybe<std::vector<std::unique_ptr<Foo>>>>;
TYPED_TEST_SUITE(FieldSerializerTraits_MaybeTest, MaybeTypes);
TYPED_TEST(FieldSerializerTraits_MaybeTest, NoOutputForFieldsIfNotJust) {
std::vector<uint8_t> out;
SerializeField(SpanFrom("maybe"), TypeParam(), &out);
EXPECT_THAT(out, testing::ElementsAreArray(std::vector<uint8_t>()));
}
TEST(FieldSerializerTraits, MaybeBool) {
std::vector<uint8_t> out;
SerializeField(SpanFrom("true"), detail::ValueMaybe<bool>(true), &out);
SerializeField(SpanFrom("false"), detail::ValueMaybe<bool>(false), &out);
std::vector<uint8_t> expected;
cbor::EncodeString8(SpanFrom("true"), &expected);
expected.push_back(cbor::EncodeTrue());
cbor::EncodeString8(SpanFrom("false"), &expected);
expected.push_back(cbor::EncodeFalse());
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
TEST(FieldSerializerTraits, MaybeDouble) {
std::vector<uint8_t> out;
SerializeField(SpanFrom("dbl"), detail::ValueMaybe<double>(3.14), &out);
std::vector<uint8_t> expected;
cbor::EncodeString8(SpanFrom("dbl"), &expected);
cbor::EncodeDouble(3.14, &expected);
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
TEST(FieldSerializerTraits, MaybePtrFoo) {
std::vector<uint8_t> out;
SerializeField(SpanFrom("foo"),
detail::PtrMaybe<Foo>(std::make_unique<Foo>(42)), &out);
std::vector<uint8_t> expected;
cbor::EncodeString8(SpanFrom("foo"), &expected);
cbor::EncodeInt32(42, &expected); // Simplified relative to production.
EXPECT_THAT(out, testing::ElementsAreArray(expected));
}
} // namespace
} // namespace v8_crdtp