Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GoogleTest test error print of enum class

I'm using GoogleTest version 1.7.0 to test my C++ application. I have an enum defined as following

namespace MyNamespace {
    enum class MyEnum {
        MyEnumValue,
        MyEnumValue2
    }
}

GoogleTest incorrectly prints it's value, resulting in this error message when the test fails:

Value of: MyClass.MyMethodThatReturnsEnum()

Actual: 4-byte object

Expected: MyEnum::MyEnumValue

Which is: 4-byte object <02-00 00-00>

Removing the class keyword produces the correct error message with the real value of the enum. Is this a known behaviour/bug of GoogleTest? Is there a way to fix the problem?

MyClass my_class;

EXPECT_EQ(MyEnum::MyEnumValue, my_class.MyMethodThatReturnsEnum());
like image 512
Stefano Avatar asked Feb 05 '15 14:02

Stefano


1 Answers

When you define constants in enum class MyEnum you define them as objects of user-defined type MyEnum from which there is no implicit conversion to any integral type. That is the goal of enum class and it's not for Googletest to assume you want objects of type MyEnum automatically converted to an integral type for the purpose of inserting to an output stream, if you have chosen to make that type an enum class and not just an enum.

So what you observe isn't a Googletest error. It's just Googletest using its fallback representation of a user-defined object of some type T for which

std::ostream & operator<<(std::ostream &, T const &);

is undefined.

If you want to see the integral values of objects of type enum class MyEnum appear in Googletest's diagnostics for a test, you have at least two ways.

One way is to simply apply the test to the underlying integral values of the objects, as in:

main.cpp (1)

#include <gtest/gtest.h>
#include <type_traits>

enum class MyEnum {
    Value,
    Value2
};

auto as_integral(MyEnum me)
-> std::underlying_type<MyEnum>::type
{
    return static_cast<std::underlying_type<MyEnum>::type>(me);
}

TEST(foo,bar)
{
    EXPECT_EQ(as_integral(MyEnum::Value),as_integral(MyEnum::Value2));
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Compile, link and run:

$ g++ -std=c++11 -Wall -Wextra -o gtester main.cpp -lgtest  -lpthread
$ ./gtester
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from foo
[ RUN      ] foo.bar
main.cpp:17: Failure
Expected equality of these values:
  as_integral(MyEnum::Value)
    Which is: 0
  as_integral(MyEnum::Value2)
    Which is: 1
[  FAILED  ] foo.bar (0 ms)
[----------] 1 test from foo (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (1 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] foo.bar

 1 FAILED TEST

Another - better - way is to provide Googletest with a definition of:

std::ostream & operator<<(std::ostream &, MyEnum const &);

that suits you. Then Googletest will use it in its diagnostics, as in:

main.cpp (2)

#include <gtest/gtest.h>
#include <type_traits>
#include <ostream>

enum class MyEnum {
    Value,
    Value2
};

auto as_integral(MyEnum me)
-> std::underlying_type<MyEnum>::type
{
    return static_cast<std::underlying_type<MyEnum>::type>(me);
}

std::ostream & operator<<(std::ostream & out, MyEnum me)
{
    return out << as_integral(me);
}

TEST(foo,bar)
{
    EXPECT_EQ(MyEnum::Value,MyEnum::Value2);
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Compile, link and run:

$ g++ -std=c++11 -Wall -Wextra -o gtester main.cpp -lgtest  -lpthread
$ ./gtester
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from foo
[ RUN      ] foo.bar
main.cpp:23: Failure
Expected equality of these values:
  MyEnum::Value
    Which is: 0
  MyEnum::Value2
    Which is: 1
[  FAILED  ] foo.bar (0 ms)
[----------] 1 test from foo (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] foo.bar

 1 FAILED TEST
like image 61
Mike Kinghan Avatar answered Sep 28 '22 04:09

Mike Kinghan