the Compartmented Robust Posix C++ Unit Test system | hosted by |
---|
A predicate is anything that can be called as if it was a
function, and that returns something that can be used as a
bool. Examples of predicates are functions (of course,)
pointers to functions, instances of classes that implement
operator ()()
.
Predicates are used with
ASSERT_PRED(pred, ...)
. Logically
ASSERT_PRED
(predicate
,
param1
, param2
,
...paramN
) is identical with
ASSERT_TRUE
(predicate
(param1
, param2
,
...paramN
)). The difference lies in error
reporting. ASSERT_PRED(pred, ...)
will list the value of each of the parameters in a violation
report, whereas
ASSERT_PRED(pred, ...)
will only
include the result.
The below example uses both versions:
#include <crpcut.hpp> bool has_substring_in(const std::string &needle, const std::string &haystack) { return haystack.find(needle) != std::string::npos; } TEST(using_assert_pred) { const char needle[] = "pqr"; const char haystack[] = "a mountain of hay"; ASSERT_PRED(has_substring_in, needle, haystack); } TEST(using_assert_true) { const char needle[] = "pqr"; const char haystack[] = "a mountain of hay"; ASSERT_TRUE(has_substring_in(needle, haystack)); } int main(int argc, char *argv[]) { return crpcut::run(argc, argv); }
The result shows the difference clearly
FAILED: using_assert_pred phase="running" -------------------------------------------------------------- /home/bjorn/devel/crpcut/doc-src/samples/simple-pred.cpp:39 ASSERT_PRED(has_substring_in, needle, haystack) param1 = pqr param2 = a mountain of hay ------------------------------------------------------------------------------- =============================================================================== FAILED: using_assert_true phase="running" -------------------------------------------------------------- /home/bjorn/devel/crpcut/doc-src/samples/simple-pred.cpp:46 ASSERT_TRUE(has_substring_in(needle, haystack)) where has_substring_in(needle, haystack) = 0 ------------------------------------------------------------------------------- =============================================================================== Total 2 test cases selected UNTESTED : 0 PASSED : 0 FAILED : 2
If a predicate has an output-stream operator defined, it will be called when making violation reports.
Sometimes you may want the type of the predicate object to be
determined by the types of one or several expressions.
crpcut solves that with the function template
crpcut::match
<pred_type>(),
together with the traits class template crpcut::match_traits.
By default, the type returned from
crpcut::match
<pred_type>()
is pred_type, and the object constructor is called
with the parameters to
crpcut::match
<pred_type>().
However, you can override the traits class template
crpcut::match_traits for your predicate class, to provide
a better suitable type, for example a specialization on the
parameters.
The above example now generalized, is unsurprisingly longer, and slightly different:
#include <crpcut.hpp> class is_substring { public: template <typename T> class implementation { public: implementation(const T t) : needle(t) {} template <typename U> bool operator()(const U* haystack) const { return operator()(std::basic_string<U>(haystack)); } template <typename U> bool operator()(const std::basic_string<U> &haystack) const { return haystack.find(needle) != std::basic_string<U>::npos; } friend std::ostream &operator<<(std::ostream &os, const implementation& i) { return os << "failed when searcing for " << i.needle; } private: T needle; }; }; namespace crpcut { template <typename T> struct match_traits<is_substring, const T*> { typedef is_substring::template implementation<const T*> type; }; template <typename T> struct match_traits<is_substring, T*> { typedef is_substring::template implementation<const T*> type; }; template <typename T> struct match_traits<is_substring, std::basic_string<T> > { typedef is_substring::template implementation<std::basic_string<T> > type; }; } TEST(using_char_array) { char needle[] = "steel"; const char hay[] = "hay"; char haystack[] = "a mountain of hay"; ASSERT_PRED(crpcut::match<is_substring>(hay), haystack); ASSERT_PRED(crpcut::match<is_substring>(needle), haystack); } TEST(using_const_char_ptr) { const char *needle = "steel"; const char *hay = "hay"; const char *haystack = "a mountain of hay"; ASSERT_PRED(crpcut::match<is_substring>(hay), haystack); ASSERT_PRED(crpcut::match<is_substring>(needle), haystack); } TEST(using_string) { std::string needle("steel"); const std::string hay("hay"); std::string haystack("a mountain of hay"); ASSERT_PRED(crpcut::match<is_substring>(hay), haystack); ASSERT_PRED(crpcut::match<is_substring>(needle), haystack); } int main(int argc, char *argv[]) { return crpcut::run(argc, argv); }
The result from running the test program is:
FAILED: using_char_array phase="running" -------------------------------------------------------------- /home/bjorn/devel/crpcut/doc-src/samples/template-pred.cpp:84 ASSERT_PRED(crpcut::match<is_substring>(needle), haystack) param1 = a mountain of hay crpcut::match<is_substring>(needle) : failed when searcing for steel ------------------------------------------------------------------------------- =============================================================================== FAILED: using_const_char_ptr phase="running" -------------------------------------------------------------- /home/bjorn/devel/crpcut/doc-src/samples/template-pred.cpp:93 ASSERT_PRED(crpcut::match<is_substring>(needle), haystack) param1 = a mountain of hay crpcut::match<is_substring>(needle) : failed when searcing for steel ------------------------------------------------------------------------------- =============================================================================== FAILED: using_string phase="running" -------------------------------------------------------------- /home/bjorn/devel/crpcut/doc-src/samples/template-pred.cpp:102 ASSERT_PRED(crpcut::match<is_substring>(needle), haystack) param1 = a mountain of hay crpcut::match<is_substring>(needle) : failed when searcing for steel ------------------------------------------------------------------------------- =============================================================================== Total 3 test cases selected UNTESTED : 0 PASSED : 0 FAILED : 3
What may be less obvious is that the above three tests instantiated is_substring::implementation<const char*> for the first two versions, and is_substring::implementation<std::string> for the last.