Search code examples
c++try-catchassertthrowgreatest-common-divisor

test a function using assert c++


I want to test the gcd function using assertions, but I don't know how to catch the exception(and prevent the program from crashing).

int gcd(int a, int b) {
if(a<0 || b<0) {
    throw "Illegal argument";
}
if(a==0 || b==0)
    return a+b;
while(a!=b) {
    if(a>b) {
        a = a - b;
    }
    else {
        b = b - a;
    }
}
return a;

}

void test_gcd() {
assert(gcd(16,24) == 8);
assert(gcd(0, 19) == 19);
try {
    gcd(5, -15);
    assert(false);
} catch (char* s) {
    assert(true);
    cout << "Illegal";
}

}


Solution

  • "I want to test the gcd function using assertions, but I don't know how to catch the exception (and prevent the program from crashing)."

    As stated in the reference documentation assert() is an implementation defined macro (emphasis mine):

    #ifdef NDEBUG
    #define assert(condition) ((void)0)
    #else
    #define assert(condition) /*implementation defined*/
    #endif
    

    If NDEBUG is not defined, then assert checks if its argument (which must have scalar type) compares equal to zero. If it does, assert outputs implementation-specific diagnostic information on the standard error output and calls std::abort. The diagnostic information is required to include the text of expression, as well as the values of the standard macros __FILE__, __LINE__, and the standard variable __func__.

    Thus assert() doesn't throw an exception you can catch. To test your code and correct usage of exceptions you should have something like the following, where expect_true() is something that prints a message, if the parameter evaluates to false and doesn't abort() your program:

    int gcd(int a, int b) {
        if(a<0 || b<0) {
            throw std::invalid_argument("a and b must be negative values");
        }
        // ...
    }
    

    #define expect_true(arg) \
            do { \
                if(!(arg)) { \
                    std::cout << "Unexpected false at " \
                              << __FILE__ << ", " << __LINE__ << ", " << __func__ << ": " \
                              << #arg \
                              << std::endl; } \
            } while(false);
    
    void test_gcd() {
        expect_true(gcd(16,24) == 8);
        expect_true(gcd(0, 19) == 19);
        bool exceptionCaught = false;
        try {
            gcd(5, -15);
        } catch (const std::invalid_argument& ex) {
            cout << "Illegal as expected" << endl;
            exceptionCaught = true;
        }
        expect_true(exceptionCaught);
    }
    

    Here's a fully working version. And another sample failing the test case.


    Also since assert() will always abort your test_gcd() function, that's a bit tedious way to do unit testing. I'd recommend using a decent unit testing framework, where you have more control over testing expectations and running various test cases. E.g. use something like Google Test (which will have an implementation for EXPECT_TRUE()).