// Copyright 2017 The Chromium OS 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 "brillo/enum_flags.h"
#include <gtest/gtest.h>
namespace brillo {
class EnumFlagsTest : public testing::Test {};
enum SomeFlagsEnum /* : int */ {
FLAG_NONE = 0,
FLAG_ONE = 1,
FLAG_TWO = 2,
FLAG_THREE = 4,
};
enum class SomeFlagsEnumClass /* : int */ {
NONE = 0,
ONE = 1,
TWO = 2,
THREE = 4,
};
enum SomeBigFlagsEnum : int64_t {
BIG_FLAG_NONE = 0,
BIG_FLAG_ONE = 1,
BIG_FLAG_TWO = 2,
BIG_FLAG_THREE = 4,
BIG_FLAG_FOUR = 8,
};
DECLARE_FLAGS_ENUM(SomeFlagsEnum);
DECLARE_FLAGS_ENUM(SomeFlagsEnumClass);
DECLARE_FLAGS_ENUM(SomeBigFlagsEnum);
// These first tests show how these operators are meant to be used.
TEST_F(EnumFlagsTest, SampleUsage) {
SomeFlagsEnum value = FLAG_NONE;
// Set a flag.
value |= FLAG_ONE;
EXPECT_EQ(FLAG_ONE, value);
// Set another
value |= FLAG_THREE;
EXPECT_EQ(FLAG_ONE | FLAG_THREE, value);
// Clear a flag
value &= ~FLAG_ONE;
EXPECT_EQ(FLAG_THREE, value);
// Toggle a flag
value ^= FLAG_TWO;
EXPECT_EQ(FLAG_THREE | FLAG_TWO, value);
}
TEST_F(EnumFlagsTest, SampleUsageOfMasks) {
SomeFlagsEnum flags = FLAG_ONE | FLAG_THREE;
EXPECT_TRUE(flags & FLAG_ONE);
EXPECT_TRUE(flags & FLAG_THREE);
EXPECT_FALSE(flags & FLAG_TWO);
EXPECT_TRUE(flags & ~FLAG_TWO);
}
TEST_F(EnumFlagsTest, SampleUsageWithEnumClass) {
SomeFlagsEnumClass value = SomeFlagsEnumClass::NONE;
// Set a flag.
value |= SomeFlagsEnumClass::ONE;
EXPECT_EQ(SomeFlagsEnumClass::ONE, value);
// Set another
value |= SomeFlagsEnumClass::THREE;
EXPECT_EQ(SomeFlagsEnumClass::ONE | SomeFlagsEnumClass::THREE, value);
// Clear a flag
value &= ~SomeFlagsEnumClass::ONE;
EXPECT_EQ(SomeFlagsEnumClass::THREE, value);
// Toggle a flag
value ^= SomeFlagsEnumClass::TWO;
EXPECT_EQ(SomeFlagsEnumClass::THREE | SomeFlagsEnumClass::TWO, value);
}
TEST_F(EnumFlagsTest, SampleUsageWithBigEnumType) {
SomeBigFlagsEnum value = BIG_FLAG_NONE;
// Set a flag.
value |= BIG_FLAG_ONE;
EXPECT_EQ(BIG_FLAG_ONE, value);
// Set another
value |= BIG_FLAG_THREE;
EXPECT_EQ(FLAG_ONE | BIG_FLAG_THREE, value);
// Clear a flag
value &= ~BIG_FLAG_ONE;
EXPECT_EQ(BIG_FLAG_THREE, value);
// Toggle a flag
value ^= BIG_FLAG_TWO;
EXPECT_EQ(BIG_FLAG_THREE | BIG_FLAG_TWO, value);
}
// These following tests verify the binary behavior of the operators. They do
// not demonstrate standard usage.
TEST_F(EnumFlagsTest, BinaryBehaviorOfAssignmentOperators) {
SomeFlagsEnum value = FLAG_NONE;
// Set a flag.
value |= FLAG_ONE;
EXPECT_EQ(1, value);
// Set another
value |= FLAG_THREE;
EXPECT_EQ(5, value);
// Clear a flag
value &= ~FLAG_ONE;
EXPECT_EQ(4, value);
// Toggle a flag
value ^= FLAG_TWO;
EXPECT_EQ(6, value);
}
TEST_F(EnumFlagsTest, BinaryBehaviorOfAssignmentOperatorsWithEnumClass) {
SomeFlagsEnumClass value = SomeFlagsEnumClass::NONE;
// Set a flag.
value |= SomeFlagsEnumClass::ONE;
EXPECT_EQ(1, static_cast<int>(value)); //
// Set another
value |= SomeFlagsEnumClass::THREE;
EXPECT_EQ(5, static_cast<int>(value));
// Clear a flag
value &= ~SomeFlagsEnumClass::ONE;
EXPECT_EQ(4, static_cast<int>(value));
// Toggle a flag
value ^= SomeFlagsEnumClass::TWO;
EXPECT_EQ(6, static_cast<int>(value));
}
TEST_F(EnumFlagsTest, BinaryBehaviorOfSimpleOperations) {
// These values are set directly with a cast for clarity.
const int all_bits_int = -1;
const SomeFlagsEnum all_bits = static_cast<SomeFlagsEnum>(all_bits_int);
const SomeFlagsEnum just_2_bits = static_cast<SomeFlagsEnum>(3);
// Inverting a flag should result in all bits set in the base type but that
// one.
EXPECT_EQ(-2, ~FLAG_ONE);
EXPECT_EQ(-3, ~FLAG_TWO);
// OR'ing two flags should result in both being set.
EXPECT_EQ(3, FLAG_ONE | FLAG_TWO);
// AND'ing two flags should result in 0.
EXPECT_EQ(FLAG_NONE, FLAG_ONE & FLAG_TWO);
// AND'ing a mask with a flag should result in that flag.
EXPECT_EQ(FLAG_ONE, all_bits & FLAG_ONE);
// XOR'ing two flags should result in both being set.
EXPECT_EQ(3, FLAG_ONE ^ FLAG_TWO);
// XOR'ing a mask with a flag should toggle that flag in the mask.
EXPECT_EQ(FLAG_ONE, FLAG_NONE ^ FLAG_ONE);
EXPECT_EQ(FLAG_TWO, just_2_bits ^ FLAG_ONE);
}
TEST_F(EnumFlagsTest, BinaryBehaviorOfSimpleOperationsOnEnumClass) {
// These values are set directly with a cast for clarity.
const int all_bits_int = -1;
const SomeFlagsEnumClass all_bits =
static_cast<SomeFlagsEnumClass>(all_bits_int);
const SomeFlagsEnumClass just_2_bits = static_cast<SomeFlagsEnumClass>(3);
// Inverting a flag should result in all bits set in the base type but that
// one.
EXPECT_EQ(-2, static_cast<int>(~SomeFlagsEnumClass::ONE));
EXPECT_EQ(-3, static_cast<int>(~SomeFlagsEnumClass::TWO));
// OR'ing two flags should result in both being set.
EXPECT_EQ(
3, static_cast<int>(SomeFlagsEnumClass::ONE | SomeFlagsEnumClass::TWO));
// AND'ing two flags should result in 0.
EXPECT_EQ(SomeFlagsEnumClass::NONE,
SomeFlagsEnumClass::ONE & SomeFlagsEnumClass::TWO);
// AND'ing a mask with a flag should result in that flag.
EXPECT_EQ(SomeFlagsEnumClass::ONE, all_bits & SomeFlagsEnumClass::ONE);
// XOR'ing two flags should result in both being set.
EXPECT_EQ(
3, static_cast<int>(SomeFlagsEnumClass::ONE ^ SomeFlagsEnumClass::TWO));
// XOR'ing a mask with a flag should toggle that flag in the mask.
EXPECT_EQ(SomeFlagsEnumClass::ONE,
SomeFlagsEnumClass::NONE ^ SomeFlagsEnumClass::ONE);
EXPECT_EQ(SomeFlagsEnumClass::TWO, just_2_bits ^ SomeFlagsEnumClass::ONE);
}
TEST_F(EnumFlagsTest, BinaryBehaviorOfSimpleOperationsWithBaseType) {
// These values are set directly with a cast for clarity.
const int64_t all_bits_int = -1;
const SomeBigFlagsEnum all_bits = static_cast<SomeBigFlagsEnum>(all_bits_int);
const SomeBigFlagsEnum just_2_bits = static_cast<SomeBigFlagsEnum>(3);
// Inverting a flag should result in all bits set in the base type but that
// one.
EXPECT_EQ(all_bits ^ BIG_FLAG_ONE, ~BIG_FLAG_ONE);
// OR'ing two flags should result in both being set.
EXPECT_EQ(3, BIG_FLAG_ONE | BIG_FLAG_TWO);
// AND'ing two flags should result in 0.
EXPECT_EQ(BIG_FLAG_NONE, BIG_FLAG_ONE & BIG_FLAG_TWO);
// AND'ing a mask with a flag should result in that flag.
EXPECT_EQ(BIG_FLAG_ONE, all_bits & BIG_FLAG_ONE);
// XOR'ing two flags should result in both being set.
EXPECT_EQ(3, BIG_FLAG_ONE ^ BIG_FLAG_TWO);
// XOR'ing a mask with a flag should toggle that flag in the mask.
EXPECT_EQ(BIG_FLAG_ONE, BIG_FLAG_NONE ^ BIG_FLAG_ONE);
EXPECT_EQ(BIG_FLAG_TWO, just_2_bits ^ BIG_FLAG_ONE);
}
} // namespace brillo