-
Notifications
You must be signed in to change notification settings - Fork 371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
maint: Use Catch2 instead of doctest #3618
Conversation
One more think to make it work - we will need to slightly change StringMaker - it should be easy: https://github.com/catchorg/Catch2/blob/devel/docs/tostring.md#catchstringmaker-specialisation (in our case we will only need to change the Before doing all that (I will need to change it for the whole repo), I would like to hear what mamba team thinks about changing test framework. |
898b999
to
c93c16e
Compare
c93c16e
to
c08aaee
Compare
@@ -0,0 +1,22 @@ | |||
#ifdef _WIN32 | |||
|
|||
// Catch compiled on `conda-forge` for MSVC doesn't support outputting `string_view`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a funny part
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think conda-forge compiles this lib for c++11 (or 14) under MSVC.
That's why automatic detection of the string_view feature in catch doesn't compile this part: https://github.com/catchorg/Catch2/blob/devel/src/catch2/catch_tostring.cpp#L131
On the other hand, when we include the header file, the automatic detection works fine, so the header part is included.
Unfortunately, an approach "1 binary works for everyone" doesn't work for C/C++ projects and by using these libraries published to conda-forge
sometimes we will have problems like this.
Thanks for tackling this! I agree that we might migrate from an unmaintai framework to a maintained one, and Catch2 seems to be the best candidate to me (I had really bad experiences with gtest in the past). The overall approach in this PR looks good to me. |
I've had a bad enough experience with gtest that I've done a gtest -> catch2 transition before in CLI11. It was worth it. :) I think doctest was really supposed to be a faster clone of catch2, and then catch2 got a lot faster with 3.0 (catch2 3.0 seems like odd versioning...), so doctest kind of doesn't have a point anymore. |
Perfect, I'm glad to see support to my proposal. Implementation update: I first thought I would have to replace It seems completely unnecessary - there is a And moreover, only some tests were using the This is how it looks:
On the left is the number of |
find_package(Catch2 REQUIRED) | ||
target_link_libraries(test_solv_cpp PRIVATE Catch2::Catch2WithMain solv::cpp) | ||
set_target_properties( | ||
test_solv_cpp PROPERTIES COMPILE_DEFINITIONS CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows us to enable nice output for many std types without having to write implementations ourselves (this is from Catch's source code):
#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
#endif
namespace doctest | ||
{ | ||
template <typename K, typename C, typename A> | ||
struct StringMaker<mamba::util::flat_set<K, C, A>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should delete this one, because Catch2 defines StringMaker for is_range
types (also defined in Catch2)
{ | ||
TEST_CASE("parse") | ||
TEST_CASE("History parse") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Catch2 doesn't like TEST_CASE
with the same name.
So I had to rename some tests in a couple of places.
I guess the same thing might have been true for doctest, but there were TEST_SUITE
s, that's why they were considered not the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the same thing might have been true for doctest, but there were TEST_SUITEs, that's why they were considered not the same
Actually I am wondering here if we shouldn't give a name to the namespace
replacing TEST_SUITE
instead of an anonymous one.
That would make it more consistent with what we had before and will give a hint on what we are testing just like the purpose of TEST_SUITE
.
I was also wondering how we would filter out tests with catch2
to run them individually?
Something equivalent to:
./test -ts=testsuite_name -tc=testcase_name -sc=subcase_name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mathbunnyru Pinging here in case the comment was missed as we are planning to merge this soon. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the same thing might have been true for doctest, but there were TEST_SUITEs, that's why they were considered not the same
Actually I am wondering here if we shouldn't give a name to the
namespace
replacingTEST_SUITE
instead of an anonymous one. That would make it more consistent with what we had before and will give a hint on what we are testing just like the purpose ofTEST_SUITE
. I was also wondering how we would filter out tests withcatch2
to run them individually? Something equivalent to:./test -ts=testsuite_name -tc=testcase_name -sc=subcase_name
I don't think having a proper namespace name will help in any way.
It is currently not consistent at all, so I would like just to remove it completely, in a separate commit, rather than have it in a few places inconsistently.
The reason it doesn't really help is because there are many ways to run Catch2 tests.
I will show it with an example of TEST_CASE("HTTPMirror")
located in test_mirror.cpp
file.
$TEST_BIN HTTPMirror
will run this test case with all 3 SECTIONs$TEST_BIN --section https HTTPMirror
will only runhttps
SECTION$TEST_BIN --filenames-as-tags [#test_mirror]
will run all the files in thetest_mirror.cpp
file- You can combine these options, for example
$TEST_BIN --filenames-as-tags --section https [#test_mirror] HTTPMirror
.
Note: $TEST_BIN --filenames-as-tags --section https [#test_mirror]
will run sections named https
, but also REQUIRE
s which are outside of SECTION
s (all that only in test_mirror.cpp
file).
From what I saw most of the time TEST_SUITE
was surrounding the whole file.
But we don't need to do that - we can just use the test filename.
Hope this helps.
@@ -201,21 +201,21 @@ TEST_SUITE("validation::v1::RootImpl") | |||
out_file.close(); | |||
|
|||
// "2.sv0.6.root.json" is not compatible spec version (spec version N) | |||
CHECK_THROWS_AS(v1::RootImpl root(p), role_file_error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Catch2 doesn't allow things like this, which is not a huge problem
@@ -12,6 +12,10 @@ set( | |||
LIBMAMBA_TEST_SRCS | |||
include/mambatests.hpp | |||
src/test_main.cpp | |||
# Catch utils | |||
src/catch-utils/conda_url.hpp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file was not included in a build tree, which is a bug. Fixed it.
@@ -3,19 +3,22 @@ | |||
// Distributed under the terms of the BSD 3-Clause License. | |||
// | |||
// The full license is in the file LICENSE, distributed with this software. | |||
#pragma once |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also was a bug
|
||
std::string StringMaker<std::byte>::convert(std::byte value) | ||
{ | ||
return fmt::format("{}", value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, the same problem for string_view under MSVC happened for std::byte
} | ||
|
||
TEST_CASE("catches_any_exceptions") | ||
{ | ||
const auto message = "expected failure"; | ||
auto result = safe_invoke([&] { throw message; }); | ||
CHECK_FALSE(result); | ||
CHECK_MESSAGE( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is no CHECK_MESSAGE in Catch, so I rewrote this code a bit
I left
These tests don't work properly on my M2 mac, unfortunately (the same is true with doctest). |
I think I will take a look if there is something nice in Catch, but I don't want to change the tests themselves, so I won't do it in this PR (and this is the only mentions of |
This is ready for reviewing, if someone wants to 😆 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Thank you, @mathbunnyru.
// Catch compiled on `conda-forge` for MSVC doesn't support outputting `std::byte`. | ||
// So we have to define StringMaker for it ourselves. | ||
// The declaration is present though, so this only causes link errors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has this problem been reported upstream? If not can we report it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I found relevant issue upstream: conda-forge/vc-feedstock#45
{ | ||
TEST_CASE("parse") | ||
TEST_CASE("History parse") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK for me.
I'm not sure I get the reason of leaving |
Both In the
Semantically, it should be Reasons I used
Reasons I used 3 CHECK statements: they do fail on my machine. |
CI fails the same way in |
@Hind-M @jjerphan @JohanMabille I think this is ready to be merged. I will get rid of the anonymous namespace in tests in a following PR (this way the diff of this PR is much more readable). |
Thank you for the hands-up. I am waiting for Hind's or Johan's approval. 🙂 |
@jjerphan Hind has approved 🎉 |
Thanks for the involved work! |
Why: mostly because
doctest
doesn't seem to be well supported: doctest/doctest#554Last commit to
main
was March 15, 2023, todev
there were only 8 commits after that.Catch2
last commit was last week, and the project is incredibly popular.Please, let me know what you think. If we decide to switch to Catch2, I will switch in all the repo.
My personal opinion:
Catch2
is easy to use, fast enough, well supported, and feels quite modern.How to switch from
doctest
toCatch2
(easy things):cmake
forfind_package
andtarget_link_libraries
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
->#define CATCH_CONFIG_MAIN
#include <doctest/doctest.h>
->#include <catch2/catch_all.hpp>
SUBCASE
->SECTION
CHECK
->REQUIRE
,CHECK_FALSE
->REQUIRE_FALSE
CHECK_EQ(a, b);
and so on ->REQUIRE(a == b);
(can be almost done with regex replacement, a bit messy when there are commas ina
orb
)A bit more complicated:
TEST_SUITE
- doesn't exist in Catch2, but we can use tags, a second arg toTEST_CASE
. I also added brackets to tag, because this is how tags look like in Catch2.Notes:
doctest is modeled after [Catch](https://github.com/catchorg/Catch2) and some parts of the code have been taken directly
(https://github.com/doctest/doctest), that's why the switch is relatively easyTEST_SUITE
was used, I addednamespace {}
, it allows to keep indentation the same so the diff is simpleREQUIRE
andCHECK
in Catch2, the difference is: TheREQUIRE
family of macros tests an expression and aborts the test case if it fails. TheCHECK
family are equivalent but execution continues in the same test case even if the assertion fails. I useREQUIRE
to fail fast.