blob: 7b5ca4d96bdcc8d89db596f9b27fd12be41804cb [file] [log] [blame] [edit]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Tests for the generated View class for Container and Box from
// nested_structure.emb.
//
// These tests check that nested structures work.
#include <array>
#include <cstdint>
#include <sstream>
#include <string>
#include <type_traits>
#include <vector>
#include "gtest/gtest.h"
#include "testdata/enum.emb.h"
namespace emboss {
namespace test {
namespace {
alignas(8) static const ::std::uint8_t kManifestEntry[14] = {
0x01, // 0:1 Kind kind == SPROCKET
0x04, 0x00, 0x00, 0x00, // 1:5 UInt count == 4
0x02, 0x00, 0x00, 0x00, // 5:9 Kind wide_kind == GEEGAW
0x20, 0x00, 0x00, 0x00, 0x00, // 9:14 Kind wide_kind_in_bits == GEEGAW
};
TEST(ManifestEntryView, CanReadKind) {
auto view = MakeAlignedManifestEntryView<const ::std::uint8_t, 8>(
kManifestEntry, sizeof kManifestEntry);
EXPECT_EQ(Kind::SPROCKET, view.kind().Read());
EXPECT_EQ(Kind::GEEGAW, view.wide_kind().Read());
EXPECT_EQ(Kind::GEEGAW, view.wide_kind_in_bits().Read());
}
TEST(ManifestEntryView, Equals) {
::std::array</**/ ::std::uint8_t, sizeof kManifestEntry> buf_x;
::std::array</**/ ::std::uint8_t, sizeof kManifestEntry> buf_y;
::std::copy(kManifestEntry, kManifestEntry + sizeof kManifestEntry,
buf_x.begin());
::std::copy(kManifestEntry, kManifestEntry + sizeof kManifestEntry,
buf_y.begin());
EXPECT_EQ(buf_x, buf_y);
auto x = MakeManifestEntryView(&buf_x);
auto x_const = MakeManifestEntryView(
static_cast</**/ ::std::array</**/ ::std::uint8_t, sizeof kManifestEntry>
*>(&buf_x));
auto y = MakeManifestEntryView(&buf_y);
EXPECT_TRUE(x.Equals(x));
EXPECT_TRUE(x.UncheckedEquals(x));
EXPECT_TRUE(y.Equals(y));
EXPECT_TRUE(y.UncheckedEquals(y));
EXPECT_TRUE(x.Equals(y));
EXPECT_TRUE(x.UncheckedEquals(y));
EXPECT_TRUE(y.Equals(x));
EXPECT_TRUE(y.UncheckedEquals(x));
EXPECT_TRUE(x_const.Equals(y));
EXPECT_TRUE(x_const.UncheckedEquals(y));
EXPECT_TRUE(y.Equals(x_const));
EXPECT_TRUE(y.UncheckedEquals(x_const));
++buf_y[1];
EXPECT_FALSE(x.Equals(y));
EXPECT_FALSE(x.UncheckedEquals(y));
EXPECT_FALSE(y.Equals(x));
EXPECT_FALSE(y.UncheckedEquals(x));
EXPECT_FALSE(x_const.Equals(y));
EXPECT_FALSE(x_const.UncheckedEquals(y));
EXPECT_FALSE(y.Equals(x_const));
EXPECT_FALSE(y.UncheckedEquals(x_const));
}
static const ::std::uint8_t kManifestEntryEdgeCases[14] = {
0xff, // 0:1 Kind kind == 0x0f
0x04, 0x00, 0x00, 0x00, // 1:5 UInt count == 4
0xff, 0xff, 0xff, 0xff, // 5:9 Kind wide_kind == MAX32BIT
0xf0, 0xff, 0xff, 0xff, 0x0f, // 9:14 Kind wide_kind_in_bits == GEEGAW
};
TEST(ManifestEntryView, EdgeCases) {
auto view = ManifestEntryView(kManifestEntryEdgeCases,
sizeof kManifestEntryEdgeCases);
EXPECT_EQ(static_cast<Kind>(255), view.kind().Read());
EXPECT_EQ(255U, static_cast</**/ ::std::uint64_t>(view.kind().Read()));
EXPECT_EQ(Kind::MAX32BIT, view.wide_kind().Read());
EXPECT_EQ(Kind::MAX32BIT, view.wide_kind_in_bits().Read());
}
TEST(Kind, Values) {
EXPECT_EQ(static_cast<Kind>(0), Kind::WIDGET);
EXPECT_EQ(static_cast<Kind>(1), Kind::SPROCKET);
EXPECT_EQ(static_cast<Kind>(2), Kind::GEEGAW);
EXPECT_EQ(
static_cast<Kind>(static_cast</**/ ::std::uint64_t>(Kind::GEEGAW) +
static_cast</**/ ::std::uint64_t>(Kind::SPROCKET)),
Kind::COMPUTED);
EXPECT_EQ(static_cast<Kind>(4294967295), Kind::MAX32BIT);
}
TEST(ManifestEntryWriter, CanWriteKind) {
::std::uint8_t buffer[sizeof kManifestEntry] = {0};
auto writer = ManifestEntryWriter(buffer, sizeof buffer);
writer.kind().Write(Kind::SPROCKET);
writer.count().Write(4);
writer.wide_kind().Write(Kind::GEEGAW);
writer.wide_kind_in_bits().Write(Kind::GEEGAW);
EXPECT_EQ(::std::vector</**/ ::std::uint8_t>(
kManifestEntry, kManifestEntry + sizeof kManifestEntry),
::std::vector</**/ ::std::uint8_t>(buffer, buffer + sizeof buffer));
EXPECT_DEATH(writer.kind().Write(Kind::LARGE_VALUE), "");
writer.kind().Write(static_cast<Kind>(0xff));
EXPECT_EQ(static_cast<Kind>(0xff), writer.kind().Read());
EXPECT_EQ(0xff, buffer[0]);
// The writes to kind() should not have overwritten the next field.
EXPECT_EQ(0x04, buffer[1]);
writer.wide_kind().Write(Kind::MAX32BIT);
writer.wide_kind_in_bits().Write(Kind::MAX32BIT);
EXPECT_EQ(::std::vector</**/ ::std::uint8_t>(
kManifestEntryEdgeCases,
kManifestEntryEdgeCases + sizeof kManifestEntryEdgeCases),
::std::vector</**/ ::std::uint8_t>(buffer, buffer + sizeof buffer));
}
TEST(Kind, EnumToName) {
EXPECT_EQ("WIDGET", TryToGetNameFromEnum(Kind::WIDGET));
EXPECT_EQ("SPROCKET", TryToGetNameFromEnum(Kind::SPROCKET));
EXPECT_EQ("MAX32BIT", TryToGetNameFromEnum(Kind::MAX32BIT));
// In the case of duplicate values, the first one listed in the .emb is
// chosen.
// TODO(bolms): Decide if this policy is good enough, or if the choice should
// be explicit.
EXPECT_EQ("LARGE_VALUE", TryToGetNameFromEnum(Kind::LARGE_VALUE));
EXPECT_EQ("LARGE_VALUE", TryToGetNameFromEnum(Kind::DUPLICATE_LARGE_VALUE));
EXPECT_EQ(nullptr, TryToGetNameFromEnum(static_cast<Kind>(100)));
}
TEST(Kind, EnumToOstream) {
{
::std::ostringstream s;
s << Kind::WIDGET;
EXPECT_EQ("WIDGET", s.str());
}
{
::std::ostringstream s;
s << Kind::MAX32BIT;
EXPECT_EQ("MAX32BIT", s.str());
}
{
::std::ostringstream s;
s << static_cast<Kind>(10005);
EXPECT_EQ("10005", s.str());
}
{
::std::ostringstream s;
s << Kind::WIDGET << ":" << Kind::SPROCKET;
EXPECT_EQ("WIDGET:SPROCKET", s.str());
}
}
TEST(ManifestEntryView, CopyFrom) {
::std::array</**/ ::std::uint8_t, 14> buf_x = {0x00};
::std::array</**/ ::std::uint8_t, 14> buf_y = {0xff};
auto x = MakeManifestEntryView(&buf_x);
auto y = MakeManifestEntryView(&buf_y);
EXPECT_NE(x.kind().Read(), y.kind().Read());
x.kind().CopyFrom(y.kind());
EXPECT_EQ(x.kind().Read(), y.kind().Read());
}
TEST(ManifestEntryView, TryToCopyFrom) {
::std::array</**/ ::std::uint8_t, 14> buf_x = {0x00};
::std::array</**/ ::std::uint8_t, 14> buf_y = {0xff};
auto x = MakeManifestEntryView(&buf_x);
auto y = MakeManifestEntryView(&buf_y);
EXPECT_NE(x.kind().Read(), y.kind().Read());
EXPECT_TRUE(x.kind().TryToCopyFrom(y.kind()));
EXPECT_EQ(x.kind().Read(), y.kind().Read());
}
TEST(Kind, NameToEnum) {
Kind result;
EXPECT_TRUE(TryToGetEnumFromName("WIDGET", &result));
EXPECT_EQ(Kind::WIDGET, result);
EXPECT_TRUE(TryToGetEnumFromName("SPROCKET", &result));
EXPECT_EQ(Kind::SPROCKET, result);
EXPECT_TRUE(TryToGetEnumFromName("MAX32BIT", &result));
EXPECT_EQ(Kind::MAX32BIT, result);
EXPECT_TRUE(TryToGetEnumFromName("LARGE_VALUE", &result));
EXPECT_EQ(Kind::LARGE_VALUE, result);
EXPECT_EQ(Kind::DUPLICATE_LARGE_VALUE, result);
EXPECT_TRUE(TryToGetEnumFromName("DUPLICATE_LARGE_VALUE", &result));
EXPECT_EQ(Kind::LARGE_VALUE, result);
EXPECT_EQ(Kind::DUPLICATE_LARGE_VALUE, result);
result = Kind::WIDGET;
EXPECT_FALSE(TryToGetEnumFromName("MAX32BIT ", &result));
EXPECT_EQ(Kind::WIDGET, result);
EXPECT_FALSE(TryToGetEnumFromName("", &result));
EXPECT_EQ(Kind::WIDGET, result);
EXPECT_FALSE(TryToGetEnumFromName(nullptr, &result));
EXPECT_EQ(Kind::WIDGET, result);
EXPECT_FALSE(TryToGetEnumFromName(" MAX32BIT", &result));
EXPECT_EQ(Kind::WIDGET, result);
EXPECT_FALSE(TryToGetEnumFromName("MAX32BI", &result));
EXPECT_EQ(Kind::WIDGET, result);
EXPECT_FALSE(TryToGetEnumFromName("max32bit", &result));
EXPECT_EQ(Kind::WIDGET, result);
}
TEST(Kind, Type) {
EXPECT_TRUE((::std::is_same</**/ ::std::uint64_t,
::std::underlying_type<Kind>::type>::value));
}
TEST(Signed, Type) {
EXPECT_TRUE((::std::is_same</**/ ::std::int64_t,
::std::underlying_type<Signed>::type>::value));
}
TEST(Foo, EnumsExposedFromView) {
EXPECT_EQ(StructContainingEnum::Status::OK,
StructContainingEnumView::Status::OK);
EXPECT_EQ(StructContainingEnum::Status::FAILURE,
StructContainingEnumView::Status::FAILURE);
}
TEST(Kind, EnumIsKnown) {
EXPECT_TRUE(EnumIsKnown(Kind::WIDGET));
EXPECT_TRUE(EnumIsKnown(Kind::SPROCKET));
EXPECT_TRUE(EnumIsKnown(Kind::GEEGAW));
EXPECT_TRUE(EnumIsKnown(Kind::COMPUTED));
EXPECT_TRUE(EnumIsKnown(Kind::LARGE_VALUE));
EXPECT_TRUE(EnumIsKnown(Kind::DUPLICATE_LARGE_VALUE));
EXPECT_TRUE(EnumIsKnown(Kind::MAX32BIT));
EXPECT_TRUE(EnumIsKnown(Kind::MAX64BIT));
EXPECT_FALSE(EnumIsKnown(static_cast<Kind>(12345)));
}
} // namespace
} // namespace test
} // namespace emboss