-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Empty generator results in segmentation fault #1593
Comments
It's not a segmentation fault, it's an assertion failure, showing that you're using Catch incorrectly. |
I should adjust my terminal color settings. I barely noticed the assertion line. It turns out my example was too minimal. This one segfaults:
But it also tells me that it crashed, because the filter didn't match anything so that's fine, i guess. Should i rather write a feature request to allow for empty generator? The problem with my custom generator still exists. |
Actually, a filter generator running out of elements will only fail that specific test case run, it won't abort the whole test run, so in this example #define CATCH_CONFIG_MAIN
#include <catch.hpp>
TEST_CASE("Empty Generator")
{
GENERATE(take(1, filter([](int i){ return i == 0; }, value(1))));
}
TEST_CASE("Bar") {
REQUIRE(1 != 2);
} the second test case will still run. This is not true with As to allowing empty generators, you would need to write a hell of a motivation for that proposal to convince me, because they were disallowed intentionally. If you have a generator that might be empty, then it should throw upon construction when it is empty so that the test case that uses it explicitly fails. The alternative is to fail it silently, but that is a trap for the user -- consider this simple example: TEST_CASE("Boring test 1") { SUCCEED(); }
TEST_CASE("Boring test 2") { SUCCEED(); }
TEST_CASE("Generator test") {
auto val = GENERATE(empty_generator());
FAIL("Not yet implemented");
} If the user compiles and runs the test binary with the current behaviour, the third |
Throwing inside the constructor looks good to me. I probably missed that in the reference. However, in my case the test case should not fail when the generator is empty. What about a "special" exception we can throw that doesn't fail the test like And sorry about the confusion about |
Fail? I don't follow. An empty generator does not represent a failure or an error of any kind. In general, generators output a variable and unpredictable numbers of items. Zero is such a number, just like one, two, a million, and so on. That is why whenever using any kind of generator/iterator, we write loops that check whether the generator has an item before attempting to use it, not after. By breaking with this convention and expecting to get an item out of a generator without checking whether it's available, Catch2's behavior here is a bug, and quite a surprising and annoying one. |
Describe the bug
A test case containing an empty generator (one that will never generate any elements) results in a segmentation fault when that test case is run.
Expected behavior
There should be no segfault. I would guess that the test case should not run at all if the generator is empty.
Reproduction steps
Compile this minimal example and run it.
Platform information:
-std=c++11
) or clang 7.0.0Additional context
Rational why i use empty generators: I modified to command line interface to accept a number of items i want to test:
These items are put into a vector which is wrapped in a generator.
Some test cases use these items and some don't. If i don't specify any items i get a segfault otherwise it works perfectly. As a work-around i could exclude the item tests from the rest but that is annoying.
It seems impossible to fix that issue with the current
IGenerator
interface as there is no way to check if the generator is empty before callingnext()
.I don't know the internals of Catch2, but these ideas came to my mind:
A different interface could look like this:
bool has_next() const
to check whether it is safe to callget_next
T get_next()
to return the current value and advance the generatorOr like python does it (i like python :) )
T next()
that return the current item and advances the generator. If the generator exhaustedthrow
an exception instead.Or use the C++ iterator concepts (these may be entirely wrong):
T operator*() const
to return the current itemoperator++()
to create the next valueoperator!=(const IGenerator<T>&) const
to compare two generatorsEdit:
Another idea, that might work with the current interface: Add a
bool empty() const
method to the generator interface with a default implementation that simply returns an internally stored flag which starts with the valuetrue
. A call tonext()
can then update the flag. An empty generator can then set that flag tofalse
in its constructor. The part that runs the tests and pulls out elements from the generator can then check theempty()
method instead.The text was updated successfully, but these errors were encountered: