Devlog #8: Unit tests for String View (Commit: 63f7ec3f88)
5 changed files with 1402 additions and 2 deletions
After building the string view module, I did what any sane person would do: wrote 110 tests for it. The new “String View” suite brings the total test count to 260 across 6 suites, and the assertion count to over 1000!!!
How the heck did you write 1402 new lines of “code” in 140 minutes?
If we exclude comments and blank lines, that’s still a lot of lines. The answer is simple: the editor I use is Neovim, which allows me to use find & replace (see first attachment), quickly copy, delete, manoeuvre lines with simple keybinds, and much more!
In the attachment you can see me writing the general structure of roughly 20 tests in one single command, thus saving me 10s of minutes. I simply then replace the test-specific data and assertions and I’m all set!
New test macro: ZINN_EXPECT_DOUBLE_EQ
Floating point equality is a lie. ZINN_EXPECT_EQ converts to uintptr_t under the hood. It being an integer type, any floating point number you convert to uintptr_t gets its floating part cut off. So I added ZINN_EXPECT_DOUBLE_EQ for checking equality of floating point numbers.
Test helpers
Two local macros keep the test file from being even longer than it already is:
EXPECT_ZINN_STRING_VIEW_NULLPTR(sv)EXPECT_ZINN_STRING_VIEW_VALID(sv, e_data, e_len)
Each macro expands to a few lines of code, which might seem pointless at first, but for 110 tests that use the macro, it adds up.
What got tested
Every public function in the string view module was tested thoroughly: null pointers, empty inputs, boundary values, and at least one “happy” path.
Constructors and macros (8 tests)
Both constructor macros are verified. from_parts rejects null data and zero length. from_cstring rejects null and empty C strings.
Slicing and trimming (23 tests)
subview is tested with the offset past the end, offset equal to length, zero count, clamping when count overshoots, exact fits, and partial slices. Each trim variant has tests for null input, no whitespace, some whitespace, all whitespace, and mixed content with whitespace only on one side.
Comparison and matching (45 tests)
equals checks length mismatch, null data on either side, the same-pointer fast path, exact match, and content mismatch.
equals_case_insensitive goes further: same categories plus non-ASCII bytes (the lookup table should pass them through unchanged) and a mismatch on the last character to make sure the loop doesn’t stop early.
starts_with and ends_with both test null data, null prefix/suffix, empty prefix/suffix (should return true), empty source (should return false), prefix/suffix longer than the source, match, and no match.
find_char tests null data, null out pointer, empty view, char not found, and found at positions first, middle, and last.
split_first has the most edge cases: null output pointers independently, null string view, empty string view, delimiter not found, delimiter at start, middle, end, and a single character that is the delimiter.
Number parsing (35 tests)
to_int64 and to_double are the heaviest. Both test null out, null data, whitespace only, trimming working, buffer overflow, overflow/underflow via ERANGE, no digits, and partial parses like "123abc".
to_int64 additionally tests positive, negative, zero, INT64_MIN, INT64_MAX, plus sign prefix, and a lone hyphen.
to_double additionally tests basic, scientific notation, negative, plus prefix, integer-only input, nan, inf, -inf, decimal-only like ".5", and a bare dot.
What’s next?
Yet another core module. Regardless of what it is, I’m still hours away from coding some fun ASCII conversions..
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.