blob: 59c9b1fb945266ac45bb085ccc0f4c911183e59b [file] [log] [blame]
// Copyright 2018 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 "src/ui/lib/escher/util/enum_flags.h"
#include <array>
#include <gtest/gtest.h>
#include "src/ui/lib/escher/impl/vulkan_utils.h"
namespace escher {
// Simple enum class with only a few members
// in sequential order with no gaps.
enum class TestEnumBits : uint8_t {
test1 = 1,
test2 = 2,
test3 = 4,
kAllFlags = 7, // test1 | test2 | test3
};
ESCHER_DECLARE_ENUM_FLAGS(TestEnumFlags, TestEnumBits);
// More complex enum class with many more members
// but likewise in sequential order with no gaps.
enum class LargeEnumBits : uint16_t {
large1 = 1U << 0,
large2 = 1U << 1,
large3 = 1U << 2,
large4 = 1U << 3,
large5 = 1U << 4,
large6 = 1U << 5,
large7 = 1U << 6,
large8 = 1U << 7,
large9 = 1U << 8,
large10 = 1U << 9,
large11 = 1U << 10,
large12 = 1U << 11,
large13 = 1U << 12,
kAllFlags = 0x1FFF,
};
ESCHER_DECLARE_ENUM_FLAGS(LargeEnumFlags, LargeEnumBits);
// Enum class where there are gaps between members.
enum class SparseEnumBits : uint32_t {
sparse1 = 1U << 2,
sparse2 = 1U << 5,
sparse3 = 1U << 9,
sparse4 = 1U << 12,
sparse5 = 1U << 17,
sparse6 = 1U << 29,
kAllFlags = sparse1 | sparse2 | sparse3 | sparse4 | sparse5 | sparse6,
};
ESCHER_DECLARE_ENUM_FLAGS(SparseEnumFlags, SparseEnumBits);
// Arrays to iterate over during testing.
static const std::array<LargeEnumBits, 13> large_enum_array = {
LargeEnumBits::large1, LargeEnumBits::large2, LargeEnumBits::large3, LargeEnumBits::large4,
LargeEnumBits::large5, LargeEnumBits::large6, LargeEnumBits::large7, LargeEnumBits::large8,
LargeEnumBits::large9, LargeEnumBits::large10, LargeEnumBits::large11, LargeEnumBits::large12,
LargeEnumBits::large13,
};
static const std::array<SparseEnumBits, 6> sparse_enum_array = {
SparseEnumBits::sparse1, SparseEnumBits::sparse2, SparseEnumBits::sparse3,
SparseEnumBits::sparse4, SparseEnumBits::sparse5, SparseEnumBits::sparse6,
};
} // namespace escher
// Basic test to make sure we can actually construct
// and assign the various enum classes.
TEST(EnumTest, Construction) {
using namespace escher;
TestEnumFlags flags;
LargeEnumFlags large_flags;
SparseEnumFlags sparse_flags;
// Assert masks have the correct C++ type.
static_assert(std::is_same<TestEnumFlags::MaskType, uint8_t>::value, "MaskType Mismatch");
static_assert(std::is_same<LargeEnumFlags::MaskType, uint16_t>::value, "Masktype Mismatch");
static_assert(std::is_same<SparseEnumFlags::MaskType, uint32_t>::value, "Masktype Mismatch");
// Assert default mask value is 0.
EXPECT_TRUE(TestEnumFlags::MaskType(flags) == 0);
EXPECT_TRUE(LargeEnumFlags::MaskType(large_flags) == 0);
EXPECT_TRUE(SparseEnumFlags::MaskType(sparse_flags) == 0);
// Assert that construction with an argument results in a
// flag with a value equal to the argument that was passed in.
flags = TestEnumFlags(TestEnumBits::test1);
EXPECT_TRUE(TestEnumFlags::MaskType(flags) == static_cast<uint8_t>(TestEnumBits::test1));
large_flags = LargeEnumFlags(LargeEnumBits::large7);
EXPECT_TRUE(LargeEnumFlags::MaskType(large_flags) ==
static_cast<uint16_t>(LargeEnumBits::large7));
sparse_flags = SparseEnumFlags(SparseEnumBits::sparse3);
EXPECT_TRUE(SparseEnumFlags::MaskType(sparse_flags) ==
static_cast<uint32_t>(SparseEnumBits::sparse3));
}
// Tests to see if the bitwise or (|) operator is working as intended.
TEST(EnumTest, BitwiseORTest) {
using namespace escher;
TestEnumFlags flags = TestEnumBits::test1 | TestEnumBits::test2;
EXPECT_TRUE(TestEnumFlags::MaskType(flags) == static_cast<uint8_t>(TestEnumBits::test1) +
static_cast<uint8_t>(TestEnumBits::test2));
flags |= TestEnumBits::test3;
EXPECT_TRUE(flags == TestEnumFlags(TestEnumBits::kAllFlags));
for (uint64_t i = 0; i < large_enum_array.size() - 1; i++) {
LargeEnumFlags flag1(large_enum_array[i]);
LargeEnumFlags flag2(large_enum_array[i + 1]);
LargeEnumFlags result = flag1 | flag2;
EXPECT_TRUE(LargeEnumFlags::MaskType(result) ==
(LargeEnumFlags::MaskType(flag1) | LargeEnumFlags::MaskType(flag2)));
}
// Or-ing all the bits together should equal 'kAllFlags'.
LargeEnumFlags large_result;
for (uint64_t i = 0; i < large_enum_array.size(); i++) {
large_result |= large_enum_array[i];
}
EXPECT_TRUE(large_result == LargeEnumFlags(LargeEnumBits::kAllFlags));
SparseEnumFlags sparse_result;
for (uint64_t i = 0; i < sparse_enum_array.size(); i++) {
sparse_result |= sparse_enum_array[i];
}
EXPECT_TRUE(sparse_result == SparseEnumFlags(SparseEnumBits::kAllFlags));
}
// Tests to see if the bitwise and (&) operators are working as intended.
TEST(EnumTest, BitwiseANDTest) {
using namespace escher;
TestEnumFlags flags;
LargeEnumFlags large_flags;
SparseEnumFlags sparse_flags;
// A flag & itself should result in the flag, a flag & another flag should
// always result in a mask tht equals 0.
for (uint64_t i = 0; i < large_enum_array.size() - 1; i++) {
LargeEnumFlags flag1(large_enum_array[i]);
LargeEnumFlags flag2(large_enum_array[i + 1]);
LargeEnumFlags result1 = flag1 & flag1;
LargeEnumFlags result2 = flag1 & flag2;
EXPECT_TRUE(LargeEnumFlags::MaskType(result1) == static_cast<uint16_t>(flag1));
EXPECT_TRUE(LargeEnumFlags::MaskType(result2) == 0);
}
for (uint64_t i = 0; i < sparse_enum_array.size() - 1; i++) {
SparseEnumFlags flag1(sparse_enum_array[i]);
SparseEnumFlags flag2(sparse_enum_array[i + 1]);
SparseEnumFlags result1 = flag1 & flag1;
SparseEnumFlags result2 = flag1 & flag2;
EXPECT_TRUE(SparseEnumFlags::MaskType(result1) == static_cast<uint32_t>(flag1));
EXPECT_TRUE(SparseEnumFlags::MaskType(result2) == 0);
}
}
// Tests to see if the bitwise XOR (^) operators are working as intended.
TEST(EnumTest, BitwiseXORTest) {
using namespace escher;
TestEnumFlags flags;
LargeEnumFlags large_flags;
SparseEnumFlags sparse_flags;
// Should be equal to zero after all of these operations.
flags = TestEnumFlags(TestEnumBits::kAllFlags);
flags ^= TestEnumBits::test1;
flags ^= TestEnumBits::test2;
flags ^= TestEnumBits::test3;
EXPECT_TRUE(flags == TestEnumFlags());
flags = TestEnumFlags();
flags ^= TestEnumBits::test1;
flags ^= TestEnumBits::test2;
flags ^= TestEnumBits::test3;
EXPECT_TRUE(flags == TestEnumFlags(TestEnumBits::kAllFlags));
for (uint64_t i = 0; i < large_enum_array.size(); i++) {
large_flags ^= large_enum_array[i];
}
EXPECT_TRUE(large_flags == LargeEnumFlags(LargeEnumBits::kAllFlags));
for (uint64_t i = 0; i < sparse_enum_array.size(); i++) {
sparse_flags ^= sparse_enum_array[i];
}
EXPECT_TRUE(sparse_flags == SparseEnumFlags(SparseEnumBits::kAllFlags));
}
// Tests that do more complicated and mixed operations.
TEST(EnumTest, StressTest) {
using namespace escher;
TestEnumFlags flags;
LargeEnumFlags large_flags;
SparseEnumFlags sparse_flags;
flags = ~flags;
large_flags = ~large_flags;
sparse_flags = ~sparse_flags;
EXPECT_TRUE(flags == TestEnumFlags(TestEnumBits::kAllFlags));
EXPECT_TRUE(large_flags == LargeEnumFlags(LargeEnumBits::kAllFlags));
EXPECT_TRUE(sparse_flags == SparseEnumFlags(SparseEnumBits::kAllFlags));
large_flags = (LargeEnumBits::large1 | LargeEnumBits::large3 | LargeEnumBits::large5 |
LargeEnumBits::large7 | LargeEnumBits::large9 | LargeEnumBits::large11 |
LargeEnumBits::large13) ^
LargeEnumBits::kAllFlags;
LargeEnumFlags large_result = LargeEnumBits::large2 | LargeEnumBits::large4 |
LargeEnumBits::large6 | LargeEnumBits::large8 |
LargeEnumBits::large10 | LargeEnumBits::large12;
EXPECT_TRUE(large_flags == large_result);
// Mix and match a bunch of different operations.
sparse_flags = (SparseEnumBits::sparse4 | SparseEnumBits::sparse6) &
(~(SparseEnumBits::sparse4 | SparseEnumBits::sparse3));
EXPECT_TRUE(sparse_flags == SparseEnumFlags(SparseEnumBits::sparse6));
sparse_flags = (~SparseEnumFlags(SparseEnumBits::sparse3) ^
SparseEnumFlags(SparseEnumBits::sparse1 | SparseEnumBits::sparse5));
EXPECT_TRUE(sparse_flags == SparseEnumFlags(SparseEnumBits::sparse2 | SparseEnumBits::sparse4 |
SparseEnumBits::sparse6));
}