base: Add unit tests for flags.hh
authorDaniel R. Carvalho <odanrc@yahoo.com.br>
Sat, 26 Dec 2020 02:31:17 +0000 (23:31 -0300)
committerDaniel Carvalho <odanrc@yahoo.com.br>
Tue, 19 Jan 2021 03:27:04 +0000 (03:27 +0000)
Add a unit test for flags.hh.

Change-Id: I58135b5f2fc016c30e1b4535f3daf46a77e99aff
Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/38714
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>

src/base/SConscript
src/base/flags.test.cc [new file with mode: 0644]

index b3d950680933079aac87db470eada6a38d3c78d2..393731449db6273c49f8bea340a0c7600b1a2507 100644 (file)
@@ -47,6 +47,7 @@ if env['USE_PNG']:
     Source('pngwriter.cc')
 Source('fiber.cc')
 GTest('fiber.test', 'fiber.test.cc', 'fiber.cc')
+GTest('flags.test', 'flags.test.cc')
 GTest('coroutine.test', 'coroutine.test.cc', 'fiber.cc')
 Source('framebuffer.cc')
 Source('hostinfo.cc')
diff --git a/src/base/flags.test.cc b/src/base/flags.test.cc
new file mode 100644 (file)
index 0000000..297abc8
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2020 Daniel R. Carvalho
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <cstdint>
+#include <limits>
+
+#include "base/flags.hh"
+
+/** Test default zero-initialized constructor. */
+TEST(FlagsTest, ConstructorZero)
+{
+    const Flags<uint32_t> flags;
+    ASSERT_EQ(uint32_t(0), uint32_t(flags));
+}
+
+/** Test constructor with a single-bit initial value. */
+TEST(FlagsTest, ConstructorSingle)
+{
+    const uint32_t value = (1 << 3);
+    const Flags<uint32_t> flags(value);
+    ASSERT_EQ(value, uint32_t(flags));
+}
+
+/** Test constructor with an initial multi-bit value. */
+TEST(FlagsTest, ConstructorMulti)
+{
+    const uint32_t value = (1 << 3) | (1 << 5) | (1 << 9);
+    const Flags<uint32_t> flags(value);
+    ASSERT_EQ(value, uint32_t(flags));
+}
+
+/** Test assignment of variable of underlying type. */
+TEST(FlagsTest, TypeAssignment)
+{
+    const uint32_t value = (1 << 3) | (1 << 5) | (1 << 9);
+    Flags<uint32_t> flags;
+    flags = value;
+    ASSERT_EQ(value, uint32_t(flags));
+}
+
+/**
+ * Test assignment of variable of underlying type, overwriting an initial
+ * value.
+ */
+TEST(FlagsTest, TypeAssignmentOverwrite)
+{
+    const uint32_t init_value = (1 << 5) | (1 << 6) ;
+    const uint32_t value = (1 << 3) | (1 << 5) | (1 << 9);
+    Flags<uint32_t> flags(init_value);
+    flags = value;
+    ASSERT_EQ(value, uint32_t(flags));
+}
+
+/** Test assignment of other Flags. */
+TEST(FlagsTest, FlagsAssignment)
+{
+    const uint32_t value = (1 << 3) | (1 << 5) | (1 << 9);
+    Flags<uint32_t> flags_a;
+    Flags<uint32_t> flags_b(value);
+    flags_a = flags_b;
+    ASSERT_EQ(uint32_t(flags_a), uint32_t(flags_b));
+}
+
+/** Test assignment of other Flags, overwriting an initial value. */
+TEST(FlagsTest, FlagsAssignmentOverwrite)
+{
+    const uint32_t init_value = (1 << 5) | (1 << 6);
+    const uint32_t value = (1 << 3) | (1 << 5) | (1 << 9);
+    Flags<uint32_t> flags_a(init_value);
+    Flags<uint32_t> flags_b(value);
+    flags_a = flags_b;
+    ASSERT_EQ(uint32_t(flags_a), uint32_t(flags_b));
+}
+
+/** Test isSet for any bit set. */
+TEST(FlagsTest, IsSetAny)
+{
+    const uint32_t value = (1 << 3);
+    const Flags<uint32_t> flags_a;
+    const Flags<uint32_t> flags_b(value);
+    ASSERT_FALSE(flags_a.isSet());
+    ASSERT_TRUE(flags_b.isSet());
+}
+
+/** Test isSet for multiple bits set. */
+TEST(FlagsTest, IsSetValue)
+{
+    const uint32_t value_a = (1 << 3);
+    const uint32_t value_b = (1 << 5);
+    const Flags<uint32_t> flags(value_a | value_b);
+    ASSERT_TRUE(flags.isSet(value_a));
+    ASSERT_FALSE(flags.isSet(value_a << 1));
+    ASSERT_TRUE(flags.isSet(value_b));
+}
+
+/** Test isSet comparing against another flag. */
+TEST(FlagsTest, IsSetType)
+{
+    const uint32_t value_a = (1 << 5) | (1 << 6);
+    const uint32_t value_b = (1 << 3) | (1 << 5) | (1 << 9);
+    const uint32_t value_c = (1 << 4) | (1 << 8);
+    const Flags<uint32_t> flags(value_a);
+    ASSERT_TRUE(flags.isSet(value_b));
+    ASSERT_FALSE(flags.isSet(value_c));
+}
+
+/** Test if all bits are set with allSet. */
+TEST(FlagsTest, AllSet)
+{
+    const uint32_t value_b = (1 << 5) | (1 << 6);
+    const uint32_t value_c = std::numeric_limits<uint32_t>::max();
+    const Flags<uint32_t> flags_a;
+    const Flags<uint32_t> flags_b(value_b);
+    const Flags<uint32_t> flags_c(value_c);
+    ASSERT_FALSE(flags_a.allSet());
+    ASSERT_FALSE(flags_b.allSet());
+    ASSERT_TRUE(flags_c.allSet());
+}
+
+/** Test allSet comparing against another flag. */
+TEST(FlagsTest, AllSetMatch)
+{
+    const uint32_t value_a = (1 << 5) | (1 << 6);
+    const uint32_t value_b = (1 << 3) | (1 << 5) | (1 << 9);
+    const Flags<uint32_t> flags(value_a);
+    ASSERT_TRUE(flags.allSet(value_a));
+    ASSERT_FALSE(flags.allSet(value_b));
+}
+
+/** Test if no bits are set with noneSet. */
+TEST(FlagsTest, NoneSet)
+{
+    const uint32_t value_b = (1 << 5) | (1 << 6);
+    const Flags<uint32_t> flags_a;
+    const Flags<uint32_t> flags_b(value_b);
+    ASSERT_TRUE(flags_a.noneSet());
+    ASSERT_FALSE(flags_b.noneSet());
+}
+
+/** Test noneSet comparing against another flag. */
+TEST(FlagsTest, NoneSetMatch)
+{
+    const uint32_t value_a = (1 << 5) | (1 << 6);
+    const uint32_t value_b = (1 << 3) | (1 << 6);
+    const uint32_t value_c = (1 << 3) | (1 << 4) | (1 << 9);
+    const Flags<uint32_t> flags(value_a);
+    ASSERT_FALSE(flags.noneSet(value_a));
+    ASSERT_FALSE(flags.noneSet(value_b));
+    ASSERT_TRUE(flags.noneSet(value_c));
+}
+
+/** Test if no bits are set after a full clear. */
+TEST(FlagsTest, Clear)
+{
+    const uint32_t value = (1 << 5) | (1 << 6);
+    Flags<uint32_t> flags(value);
+    flags.clear();
+    ASSERT_TRUE(flags.noneSet());
+}
+
+/** Test clearing specific bits. */
+TEST(FlagsTest, ClearMatch)
+{
+    const uint32_t value_a = (1 << 5) | (1 << 6);
+    const uint32_t value_b = (1 << 3) | (1 << 5) | (1 << 9);
+    Flags<uint32_t> flags(value_a);
+    flags.clear(value_b);
+    ASSERT_FALSE(flags.isSet(value_a & value_b));
+    ASSERT_TRUE(flags.isSet(value_a ^ (value_a & value_b)));
+}
+
+/** Test setting with a few overlapping bits. */
+TEST(FlagsTest, SetOverlapping)
+{
+    const uint32_t value_a = (1 << 5) | (1 << 6);
+    const uint32_t value_b = (1 << 3) | (1 << 5) | (1 << 9);
+    Flags<uint32_t> flags(value_a);
+    flags.set(value_b);
+    ASSERT_EQ(value_a | value_b, uint32_t(flags));
+}
+
+/**
+ * Test conditional set. If true the selected bits are set; otherwise, they
+ * are cleared.
+ */
+TEST(FlagsTest, ConditionalSet)
+{
+    const uint32_t value_a = (1 << 5) | (1 << 6);
+    const uint32_t value_b = (1 << 3) | (1 << 5) | (1 << 9);
+
+    Flags<uint32_t> flags_true(value_a);
+    flags_true.set(value_b, true);
+    ASSERT_EQ(value_a | value_b, uint32_t(flags_true));
+
+    Flags<uint32_t> flags_false(value_a);
+    flags_false.set(value_b, false);
+    ASSERT_EQ(value_a & ~value_b, uint32_t(flags_false));
+}
+
+/**
+ * Test updating a masked selection of bits. This means that bits of the
+ * original value that match the mask will be replaced by the bits of
+ * the new value that match the mask.
+ */
+TEST(FlagsTest, UpdateOverlapping)
+{
+    const uint32_t value_a = (1 << 4) | (1 << 5) | (1 << 6);
+    const uint32_t value_b = (1 << 3) | (1 << 5) | (1 << 9);
+    const uint32_t mask = (1 << 4) | (1 << 5) | (1 << 9) | (1 << 10);
+    // (1 << 4) is set in value_a, but is not set in value_b, so it is cleared
+    // (1 << 5) is set in both values, so it remains set
+    // (1 << 9) is not set in value_a, but it is in value_b, so it is set
+    // (1 << 10) is not set in both values, so it remains not set
+    const uint32_t result = (1 << 5) | (1 << 6) | (1 << 9);
+    Flags<uint32_t> flags(value_a);
+    flags.update(value_b, mask);
+    ASSERT_EQ(result, uint32_t(flags));
+}