A Retrospect On New Test Conversions
A Few weeks have passed and additional test files have been converted to use the clar testing framework. Only the reftable
related tests are waiting to be converted like their clar counterparts. In this blog post, I want to discuss the conversion process of the following test files went, the problems faced, and how they were mitigated;
t-oidmap.c
t-oidtree.c
t-oidarray.c
t-trailer.c
t-urlmatch-normalization
Pre-conversion stage
The test conversions kicked off with the oid
(object id) related test file. In the previous structure, all oid
related test suites were dependent on the two functions; get_oid_arbitrary_hex()
and init_hash_algo()
. init_hash_algo()
determines which hash algorithm Git should use, either from an environment variable or a default (SHA-1). get_oid_arbitrary_hex()
converts a hexadecimal string into an object ID using the selected hash algorithm. If the algorithm is unknown, it returns an error. There was a need to create a clar-based equivalent to fit the conversions of the dependent test file to use the clar testing framework.
The above helper functions were modified and enhanced to not only suit the new structure but also perform clar-based assertions which ensures that a valid hash algorithm is selected, while checking that a hex string can be correctly converted into an object ID, making them more test-oriented. The resulting helper functions were cl_setup_hash_algo()
and cl_parse_any_oid()
Now let’s break down and understand how the following test files work;
-
t-oid-array.c This code defines unit tests for handling object IDs (OIDs) in Git. It ensures that OIDs are correctly stored, sorted, and searched. The function
t_enumeration()
checks whether OIDs are properly processed and duplicates are removed, whilet_lookup()
verifies if an OID exists in an array and returns the correct index. Thefill_array()
function converts hex strings into OIDs and adds them to an array, andadd_to_oid_array()
appends an OID to an array. Thesetup()
function initializes the hash algorithm, andcmd_main()
runs all test cases. Tests are organized using macros likeTEST_ENUMERATION
andTEST_LOOKUP
, ensuring Git correctly processes and manages OIDs. -
t-oid-map.c This file tests the functionality of
oidmap
, a hash map for storing object IDs (OIDs) and their associated names. It ensures that OIDs can be inserted, retrieved, replaced, removed, and iterated over correctly. Thesetup()
function initializes the map and inserts predefined key-value pairs. Individual test functions check if entries can be replaced (t_replace()
), retrieved (t_get()
), removed (t_remove()
), and iterated over (t_iterate()
). Thecmd_main()
function runs these tests, verifying correct behavior using assertions and debug messages. -
t-oidtree.c This code tests the functionality of an
oidtree
, a data structure that stores and retrieves object IDs efficiently. It defines helper functions for insertingfill_tree_loc
and checking for object existencecheck_contains
. Thecheck_each
function verifies that iterating over stored object IDs returns expected results using a callback mechanism.The test functions
t_contains
andt_each
validate key behaviors ofoidtree
.t_contains
ensures that inserted object IDs can be correctly found or not found, whilet_each
checks that partial queries return the correct set of object IDs. The setup function initializes and clears theoidtree
for each test, ensuring test isolation.Finally,
cmd_main
runs the tests usingTEST(setup(t_contains))
andTEST(setup(t_each))
, confirming thatoidtree
insertion, lookup, and iteration work as expected. -
t-trailer.c This file tests Git’s ability to parse trailers; metadata lines like
Signed-off-by
,Fixes
, etc. from commit messages. It defines the functiont_trailer_iterator
, which initializes a trailer iterator, extracts trailer lines, and verifies that their raw text, keys, and values match the expected results. Another function,run_t_trailer_iterator
, runs multiple test cases with different commit message formats, including cases with and without body text, multiple trailer blocks, and non-trailer lines within the trailer section. The tests also ensure that Git correctly prioritizes the last trailer block and ignores dividers like---
. -
t-urlmatch-normalization.c This file contains unit tests to validate and normalize URLs using the
url_normalize
function. It ensures that different parts of a URL, such as the scheme, authority, and port, are correctly processed and normalized. The functioncheck_url_normalizable
verifies whether a given URL can be normalized, whilecheck_normalized_url
ensures that a URL is correctly transformed into an expected value. Thecompare_normalized_urls
function checks if two different URLs normalize to the same result, andcheck_normalized_url_length
validates the length of a normalized URL.The test functions, such as
t_url_scheme
,t_url_authority
, andt_url_port
, focus on specific aspects of URL validation. They test various cases, including invalid schemes, missing hosts, malformed ports, and reserved characters. The test ensures that valid URLs are handled correctly while identifying and rejecting invalid ones, maintaining consistency in URL normalization.
Conversion stage
-
u-oid-array.c The new implementation replaces macros with dedicated test functions (test_oid_array__*), making tests easier to run and maintain. It also replaces
get_oid_arbitrary_hex()
withcl_parse_any_oid()
, which provides better error handling. Assertions now usecl_assert_*
, improving failure messages. It tests storing, sorting, and looking up object IDs (OIDs) in oid_array. The functionfill_array()
converts hex strings into OIDs,t_enumeration()
ensures sorting and duplicate removal, andt_lookup()
verifies OID existence.Additionally,
test_oid_array__initialize()
handles hash algorithm setup separately, avoiding redundancy. By organizing tests into self-explanatory functions, this version follows modern testing best practices and structure, and it makes future modifications easier. This version improves modularity, readability, and integration with the Clar testing framework. -
u-oid-map.c This improves upon the previous one by transitioning the custom test framework to a more standardized and structured testing design. Instead of using a
setup()
function for initialization and cleanup, it introduces dedicated functions:test_oidmap__initialize()
andtest_oidmap__cleanup()
. This ensures better modularity and test isolation.A key improvement is the use of a global
oidmap
instance, which eliminates the need to pass the map between functions, making the code simpler. Assertions have also been improved by usingcl_assert()
andcl_assert_equal_s()
, which make the tests more readable and standardized. Additionally, failure reporting has been enhanced withcl_failf()
, which provides clearer error messages intest_oidmap__iterate()
, making debugging easier.The test structure has been refined, with each test function;
test_oidmap__replace()
,test_oidmap__get()
,test_oidmap__remove()
, andtest_oidmap__iterate()
, clearly defined and isolated. This improves maintainability and reusability, making it more modular, readable, and aligned with best practices for unit testing. -
u-oidtree.c This version improves upon the previous implementation in several key ways. The function
fill_tree_loc
has been simplified by directly callingcl_parse_any_oid(...)
instead of usingcheck_int(get_oid_arbitrary_hex(...))
. Other improvement includes the replacement ofcheck_*
macros withcl_assert_*
functions. These functions provide clearer assertion failures, making debugging easier. The update also introduces dedicated setup and teardown functions,test_oidtree__initialize()
andtest_oidtree__cleanup()
, which help maintain a structured and organized test suite.Furthermore, the function
check_each_cb
has been improved by replacing manual error messages with direct assertions usingcl_assert_equal_s(...)
, simplifying the validation process and ensuring that mismatches are detected more efficiently. -
u-trailer.c This update improves Git’s trailer parsing tests by breaking up previously combined test cases into separate, more granular tests. Instead of handling multiple scenarios within a single function, each test case now focuses on a specific aspect of trailer parsing, making it easier to understand, debug, and maintain.
The update retains all existing test cases but organizes them into distinct functions, ensuring a clearer separation of different trailer parsing behaviors. These include cases where commit messages contain no body text, multiple trailer blocks, trailers with non-trailer lines, and the effect of dividers (—). The refactoring also ensures that the last encountered trailer block takes precedence when multiple blocks are present.
By structuring the tests this way, the update improves test readability and makes debugging more efficient. Each assertion now clearly corresponds to a specific scenario, reducing ambiguity in failure reports.
-
u-urlmatch-normalization.c This encapsulates helper functions to abstract repetitive assertions, reducing duplication and making the code cleaner and easier to maintain. It also provides more comprehensive test coverage by systematically validating different aspects of URL normalization, such as scheme handling, authority validation, port handling, and port normalization.
The test cases are well-organized and grouped by specific URL components, improving readability and making it easier to debug failures. Additionally, the use of
cl_assert_equal_i
andcl_assert_equal_s
ensures precise failure messages, allowing for more effective debugging. The suite also properly manages memory by freeing dynamically allocated memory, preventing potential memory leaks.
Difficulties
The major problem encountered was before I realized that the oid
related tests are dependent on the functions I’ve discussed above. The updates tests kept failing as a result of the clar-based version not recognizing the functions because they weren’t wired up in clar. The initial solution employed was to adapt the functions in clar in our unit-test.{c,h}
files, but I soon realized with the help of my mentors that this would mean that every other test file would also depend on those functions even though they have no use for them, and this is because all clar based tests are wired through unit-test.{c,h}
, making it mandatory to add it as a header file.
Next Steps
The next thing on my agenda is to tackle the reftable
test files which would mark the final batch of test conversions to clar, whew!