For the Release 0.3 milestone of my OSD600 course, I returned to contribute to the faker-cxx
library, a C++ library designed for generating realistic fake data. As someone who had previously contributed to this project, I was eager to take on a more challenging issue. This time, I focused on increasing code coverage for a specific module.
The Issue
The function ISBN10
generates a 10-digit ISBN, sometimes with the letter "X" as the last character (representing a check digit of 10). The challenge is in the fact that this occurrence is random and relatively rare.
std::string ISBN10()
{
const auto isbn10 = string::numeric(9, true);
int sum = 0, weight = 10;
for (size_t i = 0; i < 9; i++)
{
sum += (isbn10[i] - '0') * weight;
weight--;
}
int checkDigit = sum % 11;
if (checkDigit != 0)
{
checkDigit = 11 - checkDigit;
}
if (checkDigit == 10)
{
return isbn10 + "X";
}
return isbn10 + std::to_string(checkDigit);
}
While the function works well, the existing test covered it minimally, running it once to check the result. The random nature meant edge case of generating an ISBN ending in "X" was often missed.
My Approach
Before diving into the code, I spent time understanding how ISBN generation and validation worked. The check digit calculation involves a weighted sum of the first nine digits, which must be divisible by 11. If the remainder is 10, the check digit becomes "X". This process provided the basis for writing effective tests.
The original test checked for validity but did not focus on the edge case of "X". I modified it to ensure it only handled ISBNs without "X". To address the edge case, I introduced a new test. Given the randomness, generating "X" reliably required multiple iterations which I achieved by adding a loop to maximize the chance of generating "X". As a fallback, if "X" was not generated, I used a pre-defined valid ISBN ending with "X".
feat: improve codecov for commerce module #986
This closes #907
This PR improves the test coverage for the ISBN10
function in commerce.cpp
and the associated commerce_test.cpp
file.
- Updated
shouldGenerateIsbn10
: Updated to check only ISBNs without X. - Added
shouldGenerateIsbn10WithX
: Specifically tests for the check digit - X.std::string generatedIsbn10; bool foundXCase = false; for (size_t i = 0; i < 100 && !foundXCase; i++) { generatedIsbn10 = ISBN10(); if (generatedIsbn10[9] == 'X') { foundXCase = true; } } if (!foundXCase) { generatedIsbn10 = "094339600X"; }
-
commerce.cpp
from 98% to 100%. -
commerce_test.cpp
from 96% to 99%.
Note
: While the tests achieve 99% coverage for commerce_test.cpp
, the if (!foundXCase)
branch in shouldGenerateIsbn10WithX
is intentionally left uncovered to maintain logical clarity and introduce fallback.
Challenges and Learnings
- Reviewing coverage reports with
gcov
andlcov
was instrumental in identifying the uncovered cases. - Writing tests for functions with randomness requires strategic thinking.
- Breaking tests into specific cases (e.g., with and without "X") helps ensure coverage while maintaining readability.
After my changes, the tests covered all possible outputs of the ISBN10
function, increasing overall module coverage. Although one fallback line remained technically uncovered, thorough testing and the inherent randomness of the function were finely balanced.
Top comments (0)