-
Notifications
You must be signed in to change notification settings - Fork 19
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
Integration with Catch C++ #31
Comments
Hi, If you define MOCK_ERROR_POLICY to use your own policy, there will not be any boost test related code pulled in, besides a convenience class which is just a tool and has nothing to do with the actual test framework (something called basic_cstring which is sort of a std::string_view from before it went into the standard). custom_policy::abort is supposed to abort in case of irrevocable error (like what BOOST_REQUIRE does for instance) probably by throwing an exception of some sort (or std::exit'ing or something like that but who really wants that ?). From what I can read the mapping would be
Indeed the documentation section in turtle could be improved by explaining when each of the policy function gets actually called... |
In less then 60 lines I wrote the integration. Thanks for the help. Do you plan to completely move Sourceforge repo to GitHub? What do you think to introduce an integrations directory containing integrations to various frameworks like Catch, Google Test etc. |
That's good to hear! I wouldn't mind moving away from Sourceforge, but I would like to keep the static html documentation as it is for now and would still need to host it somewhere. I don't think an 'integrations' directory would even be needed, I expect each framework integration to fit into a single header file and we could just include a catch.hpp instead of mock.hpp which would set the policy and then include mock.hpp. |
Yes, my proposal would be to have:
Not sure where to put it, thus not a Pull Request, but just a header I had. Probably it should be hardened agains GCC or Visual C++, since I only used Clang to compile my tests. And as we run Clang in a very restrictive mode I got a bunch of warnings, which probably are inevitable if Turtle Mocks should stay a header lib (e.g. weak-vtables). #ifndef TURTLE_WITH_CATCH_INTEGRATION_HPP_
# define TURTLE_WITH_CATCH_INTEGRATION_HPP_
#pragma once
#include <catch.hpp>
template<typename Result>
struct catch_turtle_mock_adapter
{
static Result abort()
{
FAIL("Aborted");
return Result(); // unreachable, used to avoid warnings
}
template<typename Context>
static void fail( const char* message
, const Context& context
, const char* file = "file://unknown-location"
, int line=0
)
{
CAPTURE(context);
FAIL_CHECK(message << " in: " << file << ":" << line);
}
template<typename Context>
static void call( const Context& context, const char* file, int line)
{
CAPTURE(context);
file = file ? file : "file://unknown-location";
INFO(file << ":" << line);
}
static void pass(const char* file, int line )
{
file = file ? file : "file://unknown-location";
INFO(file << ":" << line);
}
};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
#pragma clang diagnostic ignored "-Wextra-semi"
#pragma clang diagnostic ignored "-Wweak-vtables"
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
#pragma clang diagnostic ignored "-Wundef"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#define MOCK_ERROR_POLICY catch_turtle_mock_adapter
#include <turtle/mock.hpp>
#pragma clang diagnostic pop
#endif
|
I made a PR with the Catch integration header, see #32 I mostly changed only two things which I have pointed out in the PR, tell me what you think. |
Obviously I haven't used FakeIt (and haven't looked at the internals), however there seems to be one major difference standing out: unlike turtle it does not require to write (and compile) mock objects beforehand, probably because it makes use of (non portable compiler dependent) hook or trampoline functions of some sort. Anyway, I'll release turtle here on github and keep only the web site on sourceforge for the time being as you suggested, not that I think it will really change much but it's easy enough. |
Actually I just realized github provides support for static web sites, e.g. https://help.github.com/articles/creating-project-pages-using-the-command-line/ so there is no real need for keeping sourceforge around. I have also started #33 feel free to comment in there if you wish. |
Hi Mathieu, I hope to find more time within the next 2 weeks and finish the port to Catch++. Sorry for the delay. That's not that easy, but somehow, just not enough time right now. Greetings, |
Hey no worries, I know how it is 🏃 Cheers, |
FWIW here is how INFO is defined
with
and finally
so I suppose instead of using INFO in the turtle integration layer we should do
(Actually I am not entirely sure we should log anything in this case.) |
Hi Mathieu, I am now experimenting with the Catch support and resolution of the line number problems discussed above. Currently I face the following behaviour and I am not sure it is right. Let me describe it. Suppose I have a simple function: void foo(message_type const& m, std::promise<std::string>&& p)
{
if(!protocol_type::has_reply(m.id)
{
p.set_value(encoder_type::encode_ack(m.id));
return;
}
reply_queue_.enqueue(std::make_tuple(m.id, std::move(p));
} Now I mocked Actually there are 2 possible flows, which seem to be not so descriptive:
Another issue the implementation I changed the way how [[noreturn]] static Result abort()
{
do
{
FAIL("=> aborting test case due to failing mock expectations!");
}while(true);
} Would be great to hear your thoughts, than I can submit a patch. |
I think I now better understand the entire flow and structure. I've posted to Catch Google Group this question about Turtle integration: |
Hi Ovanes, I'll try and answer as best as I can. First I don't think you should bother much with 'pass'. If a test framework does not have that feature it shouldn't be a big deal and you could always leave it empty if INFO does not meet the need. See www.boost.org/libs/test/doc/html/boost_test/test_output/test_tools_support_for_logging/checkpoints.html for more information. Now in order to avoid the infinite do/while you can throw an exception.
or you can try directly
because in theory 'abort' should only cope with aborting the test, the actual logging being taken care of by 'fail'. As for the issue with 'never', what does your implementation of 'fail' look like ? |
Hi Mathieu, this is my current sketch. After it I'll quote and explain some things... #include <catch.hpp>
#include <cassert>
template<typename Result>
struct catch_turtle_mock_adapter
{
[[noreturn]] static Result abort()
{
FAIL("=> aborting test case due to failing mock expectations!");
assert(false && "Unreachable throw statement reached!");
throw std::runtime_error("Unreachable throw statement reached!");
}
static auto source_line_info(const char* file, int line)
{
file = (file) ? file : "file://unknown-location";
return ::Catch::SourceLineInfo{file, static_cast<size_t>(line)};
}
template<class SourceLineInfo>
static auto message_builder( std::string const& severity
, SourceLineInfo const& info
, ::Catch::ResultWas::OfType numeric_severity
= ::Catch::ResultWas::Info
)
{
return ::Catch::MessageBuilder{severity, info, numeric_severity};
}
template<typename Context>
static void fail( const char* message
, const Context& context
, const char* file = "file://unknown-location"
, int line=0
)
{
using namespace Catch;
auto info = source_line_info(file, line);
ScopedMessage capturedContext
{ message_builder("CAPTURE", info)
<< "context := " << ::Catch::toString(context)
}
;
do{
Catch::ResultBuilder result
{"FAIL_CHECK", info, "", Catch::ResultDisposition::ContinueOnFailure}
;
result << message << " in: " << file << ":" << line
<< "" + ::Catch::StreamEndStop()
;
result.captureResult(Catch::ResultWas::ExplicitFailure);
INTERNAL_CATCH_REACT(result)
} while(::Catch::alwaysFalse());
}
template<typename Context>
static void call(const Context& context, const char* file, int line)
{
file = file ? file : "file://unknown-location";
using namespace Catch;
auto info = source_line_info(file, line);
ScopedMessage capturedContext
{ message_builder("CAPTURE", info)
<< "context := " << ::Catch::toString(context)
}
;
ScopedMessage scopedMessage
{ message_builder("INFO", info) << file << ":" << line }
;
}
static void pass(const char* file, int line )
{
file = file ? file : "file://unknown-location";
using namespace Catch;
auto info = source_line_info(file, line);
ScopedMessage scopedMessage
{ message_builder("INFO", info) << file << ":" << line }
;
}
}; In Catch
Given the above execution logic, it is not only about We could work around it by having an own stack of objects, where In general, what I think of is to have a typedef inside the adapter type with the context type. A reference to the instance of that type is passed to every adapter member then and is managed by Turtle itself. Each adapter function then decides if it wants to put something in this context or not. It can be cheaply to implement that behaviour in case of current adapters, because they'd just use some some empty type as context and do nothing with it. What do you think? |
I think discussing the code would be easier if it were on a branch 😄 What I notice first is that 'fail' is not supposed to do more than log. It should not throw, see for instance https://github.com/mat007/turtle/blob/master/include/turtle/detail/function_impl_template.hpp#L54 where 'fail' is being called in a loop. Actually both 'call' and 'pass' purpose is only to log information to the user. Also why couldn't we bypass the error message stack entirely? After all we already know there is an error by the time 'fail' gets called.
e.g. what ScopedMessage constructor does? |
Regarding On the other hand, I am not sure if Catch expects
I agree. Let's do it this way. I will fork your repo at Github and implement my ideas, than we can review them... |
I was previously using Turtle Mock with Boost.Test and was pretty happy, but now we decided to switch to Catch C++ and Turtle Mock does not work any more :(
I had a look at different C++ Mock frameworks and still convinced no other framework is that good as Turtle Mock for various reasons.
I read this documentation Link on how to integrate Turtle Mock with other Frameworks but still can't understand all the details.
Documentation example
My Questions
custom_policy
is going to be provided will there be any kind of dependency to Boost.Test?custom_policy::abort
do and what kind ofResult
instance should it return? Especially if Result type is used by Turtle Mock in template instantiation.pass
seems to be easily mappable to CatchINFO
call
andfail
introduce a context in addition to thepass
data being used. I think the context can be mapped to CatchCAPTURE
call as it is also lazy:Many thanks in advance for answering these questions!
The text was updated successfully, but these errors were encountered: