tests: introduce doctest infra + migrate llcommon/llmath/llcorehttp subsets (ctest green) [relates to #4445]#4852
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
|
What are the changes to .gitignore and .gitattributes for? They seem in no relation to doctest and counterproductive, |
5fb6af0 to
dddc098
Compare
|
@Ansariel Thanks for the note! I’ve dropped the unrelated .gitignore/.gitattributes edits so this PR stays focused on doctest. |
There was a problem hiding this comment.
Pull Request Overview
This PR introduces a doctest-based unit testing framework to complement the existing TUT infrastructure, migrating initial test suites for llcommon, llmath, and llcorehttp. The changes keep the current TUT framework intact while establishing new doctest targets for gradual migration.
Key Changes
- Added header-only doctest framework with shared test helpers (
LL_CHECK_*macros for floating-point, range, and buffer comparisons) - Migrated 227 test cases across three modules:
llcommon_doctest(100 cases),llmath_doctest(93 cases),llcorehttp_doctest(34 cases) - Created deterministic HTTP test fakes (zero-latency transport, monotonic clock, queued responses) for network-free testing
Reviewed Changes
Copilot reviewed 66 out of 68 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tools/testing/gen_tut_to_doctest.py |
Python script to auto-generate doctest stubs from TUT sources |
indra/test/{doctest_main.cpp,ll_doctest_helpers.h,tut_compat_doctest.h} |
Shared doctest infrastructure and TUT compatibility layer |
indra/llmath/tests_doctest/*.cpp |
Migrated vector/matrix/quaternion math tests to doctest |
indra/llcorehttp/tests_doctest/{http_fakes.h,http_fakes.cpp} |
Deterministic HTTP testing infrastructure |
indra/llcorehttp/tests_doctest/*_test_doctest.cpp |
Migrated HTTP component tests with fake transport |
indra/llcommon/tests_doctest/*_test_doctest.cpp |
Auto-generated TODO stubs for future llcommon migration |
indra/viewer_components/login/tests/lllogin_doctest.cpp |
New doctest-based login workflow tests |
indra/*/CMakeLists.txt |
Build configuration for new doctest targets |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Hey @akleshchev Thanks a lot for taking a look and for requesting the review here. Just to clarify: this PR is only meant to be a first step for a doctest-based test setup, not the full migration. I wanted to get early feedback before going any further. I also saw on Discord that Signal is stepping away, and I really appreciate that @Geenz is keeping the open source program moving forward. If this approach to the doctest infra, the CMake wiring and the way I’m migrating these first tests looks reasonable from your side, I’m happy to continue in follow-up PRs and adjust things to match what you’d like to see in the test suite. No rush at all, I know there’s a lot happening right now. Just wanted to make the intent clear and let you know I’m around to iterate on this. |
That's obvious from the todo) We do need a replacement, but with signal away I don't know who is responsible for the commisions, will ask around. P.S. You probably can make an AI do the bulk of the work here |
…ubsets (ctest green) Signed-off-by: Maycon Bekkers <mayconbekkers@gmail.com>
dddc098 to
4e3aeda
Compare
|
Quick follow-up on the doctest infra:
Locally (RelWithDebInfoOS,
All green ( |
|
Updated this with the cleaned stack. I also kept only the minimal |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 90 out of 144 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #include "../llcommon/lltimer.h" | ||
| // for lltrace class | ||
| #include "../llcommon/lltrace.h" |
There was a problem hiding this comment.
These relative includes look incorrect for indra/llimage/tests_doctest (they would resolve to indra/llimage/llcommon/...). Since the target already adds ${CMAKE_SOURCE_DIR}/llcommon to include paths, include the headers via the public include form (e.g., #include \"lltimer.h\" / #include \"lltrace.h\") or another correct path to avoid build breaks on clean checkouts.
| #include "../llcommon/lltimer.h" | |
| // for lltrace class | |
| #include "../llcommon/lltrace.h" | |
| #include "lltimer.h" | |
| // for lltrace class | |
| #include "lltrace.h" |
| responder_test(bool* res) | ||
| { | ||
| done = res; | ||
| *done = false; | ||
| } | ||
| virtual void completed(bool success, const std::string& error_message, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) | ||
| { | ||
| *done = true; | ||
| } |
There was a problem hiding this comment.
done is written from the decode thread and read from the main test thread without synchronization, which is a data race (UB) even if it 'usually works'. Use std::atomic_bool (or a condition_variable) for cross-thread completion signaling, and consider replacing the polling sleep loop with a proper wait/notify to reduce flakiness and runtime.
| mThread = new LLImageDecodeThread(true); | ||
| ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL); | ||
| // Insert something in the queue | ||
| bool done = false; |
There was a problem hiding this comment.
done is written from the decode thread and read from the main test thread without synchronization, which is a data race (UB) even if it 'usually works'. Use std::atomic_bool (or a condition_variable) for cross-thread completion signaling, and consider replacing the polling sleep loop with a proper wait/notify to reduce flakiness and runtime.
| while ((done == false) && (total_time < MAX_TIME)) | ||
| { | ||
| ms_sleep(INCREMENT_TIME); | ||
| total_time += INCREMENT_TIME; | ||
| } |
There was a problem hiding this comment.
done is written from the decode thread and read from the main test thread without synchronization, which is a data race (UB) even if it 'usually works'. Use std::atomic_bool (or a condition_variable) for cross-thread completion signaling, and consider replacing the polling sleep loop with a proper wait/notify to reduce flakiness and runtime.
| // Check a selection of bad group names from the crash reports | ||
| LLDirIterator iter(".","+bad-group-name]+?\?-??.*"); | ||
| LLDirIterator iter1(".","))--@---bad-group-name2((?\?-??.*\\.txt"); | ||
| LLDirIterator iter2(".","__^v--x)Cuide d sua vida(x--v^__?\?-??.*"); |
There was a problem hiding this comment.
These variables are intentionally unused (construction-only), which can trigger -Wunused-variable warnings and fail builds when warnings are treated as errors. Mark each as [[maybe_unused]] or explicitly cast to void (e.g., (void)iter;) after construction.
| LLDirIterator iter2(".","__^v--x)Cuide d sua vida(x--v^__?\?-??.*"); | |
| LLDirIterator iter2(".","__^v--x)Cuide d sua vida(x--v^__?\?-??.*"); | |
| (void)iter; | |
| (void)iter1; | |
| (void)iter2; |
| # ifdef LL_DEBUG | ||
| // skip("This test fails on Windows when compiled in debug mode."); | ||
| # endif |
There was a problem hiding this comment.
This test suite contains (1) a known debug-mode failure note that is currently commented out, and (2) std::cout output inside a loop. Both can cause noisy or flaky CI runs (especially under Debug builds). Prefer a proper doctest skip in LL_DEBUG (e.g., DOCTEST_SKIP) and remove the console output (or gate it behind a debug flag) to keep test runs deterministic and quiet.
| TUT_ENSURE("LLAligment veca base", is_aligned(veca,16)); | ||
| for(int i=0; i<ARR_SIZE; i++) | ||
| { | ||
| std::cout << "veca[" << i << "]" << std::endl; |
There was a problem hiding this comment.
This test suite contains (1) a known debug-mode failure note that is currently commented out, and (2) std::cout output inside a loop. Both can cause noisy or flaky CI runs (especially under Debug builds). Prefer a proper doctest skip in LL_DEBUG (e.g., DOCTEST_SKIP) and remove the console output (or gate it behind a debug flag) to keep test runs deterministic and quiet.
docs/testing/doctest_quickstart.md
Outdated
| - Build targets: `llcommon_doctest` (subset of llcommon tests), `llmath_doctest`, `llcorehttp_doctest`, `login_doctest` | ||
| - Run: `ctest -C RelWithDebInfo -R "(llcommon_doctest|llmath_doctest|llcorehttp_doctest|login_doctest)" -V` |
There was a problem hiding this comment.
The quickstart references login_doctest, but this PR's CMake changes only add doctest executables for llcommon/llmath/llcorehttp (plus a few other modules) and no login_doctest target is introduced in the provided diffs. Either add the missing target or remove/update login_doctest from the quickstart so instructions match what actually builds.
| recorded_locations.push_back(headers->find("Location") ? *headers->find("Location") : std::string()); | ||
| recorded_content_types.push_back(headers->find("Content-Type") ? *headers->find("Content-Type") : std::string()); |
There was a problem hiding this comment.
headers->find(...) is called twice per header name in the ternary expressions. Store the result of find() in a local pointer/optional and reuse it to avoid redundant lookups and keep the code easier to read.
| recorded_locations.push_back(headers->find("Location") ? *headers->find("Location") : std::string()); | |
| recorded_content_types.push_back(headers->find("Content-Type") ? *headers->find("Content-Type") : std::string()); | |
| auto location = headers->find("Location"); | |
| recorded_locations.push_back(location ? *location : std::string()); | |
| auto content_type = headers->find("Content-Type"); | |
| recorded_content_types.push_back(content_type ? *content_type : std::string()); |
| LLCore::HttpHandle FakeTransport::nextHandle() | ||
| { | ||
| ++mNextId; | ||
| return reinterpret_cast<LLCore::HttpHandle>(mNextId); |
There was a problem hiding this comment.
Casting an incrementing integer to HttpHandle with reinterpret_cast is implementation-defined (and potentially problematic if HttpHandle is a pointer type on some platforms/ABIs). Prefer generating handles in the same representation as HttpHandle (e.g., if it is integral, use static_cast; if it is pointer-like, consider storing an internal uintptr_t and converting via a well-defined helper, or use the production handle generator if available).
| return reinterpret_cast<LLCore::HttpHandle>(mNextId); | |
| return static_cast<LLCore::HttpHandle>(mNextId); |
|
Lots of 'todos'. |
Relates to #4445.
This PR adds a header-only doctest setup and migrates a first wave of unit tests while keeping the legacy TUT harness for suites not yet ported. The goal is to land a minimal, working baseline that the team can iterate on module by module.
This affects only unit-test targets behind LL_TESTS=ON; viewer runtime and packages are unchanged.
What’s included
How to run locally
Scope / non-goals
Does not change viewer runtime or packaging.
TUT remains for non-migrated suites; removal will happen after follow-ups when coverage is sufficient.
Proposed follow-ups
Continue migrating remaining suites per module (llcommon -> llmath -> llcorehttp -> newview/test).
Once coverage is high enough, remove Tut.cmake glue and clean up LLAddBuildTest.cmake usage.