Chapter 5 Extention: Introducing doctest

doctest is a software framework for unit testing in C++. Since it is light weight, comparatively easy to use, and free software, we will begin using it for exercises for the remainder of the book.

Appendix B: A development environment for unit testing has instructions for configuring your computer for using doctest.

We’ll begin here with an example from the chapter, which we’ll put in a file named test_absolute_value.cpp.

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest.h>
using namespace std;

double absolute_value(double x) {
    if (x < 0) {
        return -x;
    }
    return x;
}

TEST_CASE("Test absolute_value") {
    CHECK(absolute_value(4) == 4);
    CHECK(absolute_value(-4) == 4);
    CHECK(absolute_value(0) == 0);
}

Compiling this test_absolute_value.cpp source file with:

$ g++ text_absolute_value.cpp

and then running:

$ ./a.out

yields:

$ ./a.out
[doctest] doctest version is "2.5.0"
[doctest] run with "--help" for options
===============================================================================
[doctest] test cases: 1 | 1 passed | 0 failed | 0 skipped
[doctest] assertions: 3 | 3 passed | 0 failed |
[doctest] Status: SUCCESS!

Trying It Out

The functions distance, area, is_single_digit, and factorial were also presented in this chapter. Write doctests for each of them using the absolute_value example as a model.

Exercises

In each of the following exercises, create a file with the following scaffolding and then modify it according to the given problem:

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest.h>
using namespace std;

// Your function goes here

TEST_CASE("...") {
    CHECK(...);
}
  1. Create a file named test_is_even.cpp that has the a function definition of is_even(int) that passes the following tests:

    TEST_CASE("is_even identifies even numbers") {
        CHECK(is_even(0) == true);
        CHECK(is_even(2) == true);
        CHECK(is_even(-4) == true);
        CHECK(is_even(1) == false);
        CHECK(is_even(-7) == false);
    }
    
  2. Create a file named test_find_largest.cpp that has unit tests for a function named find_largest(int x, int y) that takes two integers as arguments and returns the larger of the two.

    TEST_CASE("find_largest returns the greater of two integers") {
        CHECK(find_largest(6, 19) == 19);
        CHECK(find_largest(6, 1) == 6);
        CHECK(find_largest(22, 42) == 42);
        CHECK(find_largest(42, 42) == 42);
    }
    
  3. Create a file named test_sum_to_n.cpp that takes a positive integer, n, as an argument and computes the sum of all integers from 1 to n.

    TEST_CASE("sum_to_n(int n) returns sum of integers from 1 to n") {
        CHECK(sum_to_n(3) == 6);
        CHECK(sum_to_n(7) == 28);
        CHECK(sum_to_n(1) == 1);
        CHECK(sum_to_n(42) == 903);
    }
    
  4. Create a file named test_count_digits.cpp that takes a positive integer, n, as an argument and returns the number of decimal digits it contains.

    TEST_CASE("count_digits(int n) returns number of decimal digits in n") {
        CHECK(count_digits(7) == 1);
        CHECK(count_digits(73) == 2);
        CHECK(count_digits(999) == 3);
        CHECK(count_digits(0) == 1);
        CHECK(count_digits(100000) == 6);
        CHECK(count_digits(0xFF) == 3);
        CHECK(count_digits(0123) == 2);
    }
    
  5. Create a file named test_count_digits.cpp that takes a non-negative integer, n, as an argument and returns the number of decimal digits it contains.

    TEST_CASE("count_digits(int n) returns number of decimal digits in n") {
        CHECK(count_digits(7) == 1);
        CHECK(count_digits(73) == 2);
        CHECK(count_digits(999) == 3);
        CHECK(count_digits(0) == 1);
        CHECK(count_digits(100000) == 6);
        CHECK(count_digits(0xFF) == 3);
        CHECK(count_digits(0123) == 2);
    }
    
  6. Create a file named test_sum_of_squares_to_n.cpp that takes a positive integer, n, as an argument and returns the sum of the squares of the integers from 1 to n.

    TEST_CASE("sum_of_squares_to_n(int n) sums squares from 1 to n") {
        CHECK(sum_of_squares_to_n(1) == 1);
        CHECK(sum_of_squares_to_n(3) == 14);
        CHECK(sum_of_squares_to_n(5) == 55);
        CHECK(sum_of_squares_to_n(6) == 91);
    }
    
  7. Create a file named is_divisible_by.cpp that takes two positive integers, n and d, as an arguments and returns true if n is divisible by d and false otherwise.

    TEST_CASE("is_divisible_by(int n, int d) returns whether d divides n") {
        CHECK(is_divisible_by(10, 5) == true);
        CHECK(is_divisible_by(10, 3) == false);
        CHECK(is_divisible_by(3, 10) == false);
        CHECK(is_divisible_by(0, 7) == true);
    }
    
  8. Create a file named is_prime.cpp that takes a positive integer, n, as an argument and returns true if n is prime number and false otherwise.

    TEST_CASE("is_prime(int n) returns true if n is a prime number") {
        CHECK(is_prime(0) == false);
        CHECK(is_prime(1) == false);
        CHECK(is_prime(2) == true);
        CHECK(is_prime(3) == true);
        CHECK(is_prime(4) == false);
        CHECK(is_prime(9) == false);
        CHECK(is_prime(19) == true);
        CHECK(is_prime(27) == false);
    }
    
  9. Create a file named test_count_odd_digits.cpp that takes a non-negative integer, n, as an argument and returns the number of odd decimal digits it contains.

    TEST_CASE("count_odd_digits(int n) returns number of odd decimal digits in n") {
        CHECK(count_odd_digits(73) == 2);
        CHECK(count_odd_digits(723) == 2);
        CHECK(count_odd_digits(888) == 0);
        CHECK(count_odd_digits(0) == 0);
        CHECK(count_odd_digits(103002) == 2);
        CHECK(count_odd_digits(0xFF) == 1);
        CHECK(count_odd_digits(0123) == 2);
    }
    
  10. Create a file named test_gcd.cpp that takes two non-negative integers, n and m, and returns the greatest common divisor (GCD) between them. integer, n, as an argument and returns the number of odd decimal digits it contains.

    TEST_CASE("gcd(int n, int m) returns the GCD of n and m") {
        CHECK(gcd(12, 8) == 4);
        CHECK(gcd(48, 18) == 6);
        CHECK(gcd(7, 13) == 1);
        CHECK(gcd(294, 210) == 42);
        CHECK(gcd(19, 19) == 19);
    }
    
  11. Create a file named test_lcm.cpp that takes two non-negative integers, n and m, and returns the least common multiple (LCM) between them.

    TEST_CASE("lcm(int n, int m) returns the LCM of n and m") {
        CHECK(lcm(12, 20) == 60);
        CHECK(lcm(3, 5) == 15);
        CHECK(lcm(6, 10) == 30);
        CHECK(lcm(7, 7) == 7);
        CHECK(lcm(24, 56) == 168);
    }
    
  12. Create a file named test_largest_digit.cpp that takes an integer, n, as an argument and returns the largest digit in the decimal representaion of n.

    TEST_CASE("largest_digit(int n) returns the largest digit in n") {
        CHECK(largest_digit(0) == 0);
        CHECK(largest_digit(1030) == 3);
        CHECK(largest_digit(7986) == 9);
        CHECK(largest_digit(-584) == 8);
        CHECK(largest_digit(0xFF) == 5);
        CHECK(largest_digit(0123) == 8);
    }