harishaj90
harishaj90

Reputation: 132

ASSERT_THROW: error: void value not ignored as it ought to be

I am beginner to gtest. I trying to use ASSERT_THROW will compilation fail. Could anyone help on this:

class my_exp {};

int main(int argc, char *argv[])
{
   EXPECT_THROW(throw my_exp(), my_exp); // this will pass
   // This will through below compilation error 
   ASSERT_THROW(throw my_exp(), my_exp); 
   return 0;
}

Compilation output:

ERROR : 
In file included from /usr/include/gtest/gtest.h:57:0,
             from gtest.cpp:1:
gtest.cpp: In function ‘int main(int, char**)’:
gtest.cpp:12:3: error: void value not ignored as it ought to be
    ASSERT_THROW(throw my_exp(), my_exp); 
    ^

Upvotes: 6

Views: 10080

Answers (1)

Gluttton
Gluttton

Reputation: 5958

Short version

You write test in the wrong way, to write test you should put assertion inside test (macro TEST) or test fixtures (macro TEST_F).

Long version

1 . What's really happens?

To find out the real problem is not easy because the Google Testing Framework use macros which hide real code. To see code after macro substitution is required to perform preprocessing, something like this:

g++ -E main.cpp -o main.p

The result of preprocessing when using ASSERT_THROW will be looks like this (after formatting):

class my_exp {};

int main(int argc, char *argv[])
{
    switch (0)
        case 0:
        default:
        if (::testing::internal::ConstCharPtr gtest_msg = "") {
            bool gtest_caught_expected = false;
            try {
                if (::testing::internal::AlwaysTrue () ) {
                    throw my_exp ();
                };
            } catch (my_exp const &) {
                gtest_caught_expected = true;
            } catch (...) {
                gtest_msg.value = "Expected: throw my_exp() throws an exception of type my_exp.\n Actual: it throws a different type.";
                goto gtest_label_testthrow_7;
            } if (!gtest_caught_expected) {
                gtest_msg.value = "Expected: throw my_exp() throws an exception of type my_exp.\n  Actual: it throws nothing.";
                goto gtest_label_testthrow_7;
            }
        }
        else
            gtest_label_testthrow_7:
            return ::testing::internal::AssertHelper (::testing::TestPartResult::kFatalFailure, "main.cpp", 7, gtest_msg.value) = ::testing::Message ();

    return 0;
}

For EXPECT_THROW result will be the same except some difference:

    else
        gtest_label_testthrow_7:
        ::testing::internal::AssertHelper (::testing::TestPartResult::kNonFatalFailure, "main.cpp", 7, gtest_msg.value) = ::testing::Message ();

2 . OK, the reason of different behaviour is found, let's continue.

In the file src/gtest.cc can be found AssertHelper class declaration including assignment operator which return void:

void AssertHelper::operator=(const Message& message) const

So now reason of the compiler complain is clarified.

3 . But why this problem is caused is not clear. Try realise why for ASSERT_THROW and EXPECT_THROW different code was generated. The answer is the macro from file include/gtest/internal/gtest-internal.h

#define GTEST_FATAL_FAILURE_(message) \
  return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)

#define GTEST_NONFATAL_FAILURE_(message) \
  GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)

which contain return for fatal case.

4 . But now is question why this assertions usually works well?

To answer of this question try investigate code snipped which written in correct way when assertion is placed inside test:

#include <gtest/gtest.h>

class my_exp {};

TEST (MyExp, ThrowMyExp)
{
    ASSERT_THROW (throw my_exp (), my_exp);
}

To exclude pollution of the answer I just notice that in such case the return statement for ASSERT_THROW also exist, but it is placed inside method:

void MyExp_ThrowMyExp_Test::TestBody ()

which return void! But in your example assertions are placed inside main function which return int. Looks like this is source of problem!

Try prove this point with simple snippet:

void f1 () {};
void f2 () {return f1();};
//int  f2 () {return f1();}; // error here!

int main (int argc, char * argv [])
{
    f2;
    return 0;
}

5 . So the final answer is: the ASSERT_THROW macro contain return statement for expression which evaluates to void and when such expression is placed into function which return non void value the gcc complain about error.

P.S. But anyway I have no idea why for one case return is used but for other case is not.

Update: I've asked this question on GitHub and got the following answer:

ASSERT_XXX is used as a poor man's exception to allow it to work in environments where exceptions are disabled. It does a return; instead. It is meant to be used from within the TEST() methods, which return void.

Update: I've just realised that this question described in the official documentation:

By placing it in a non-void function you'll get a confusing compile error > like "error: void value not ignored as it ought to be".

Upvotes: 17

Related Questions