the Compartmented Robust Posix C++ Unit Test system

General predicates

General Predicates are used with ASSERT_PRED(pred, ...) or VERIFY_PRED(pred, ...). Logically ASSERT_PRED(predicate, param1, param2, ...paramN) is identical with ASSERT_TRUE(predicate(param1, param2, ...paramN)), and likewise for VERIFY_PRED(). The difference lies in error reporting. ASSERT_PRED(pred, ...) and VERIFY_PRED(pred, ...) will list the value of each of the parameters in a violation report, whereas ASSERT_TRUE(expr) and VERIFY_TRUE(expr) will give a cruder report with fewer details.

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"  --------------------------------------------------------------
     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"  --------------------------------------------------------------
     samples/simple-pred.cpp:46
     ASSERT_TRUE(has_substring_in(needle, haystack))
       is evaluated as:
         0
     -------------------------------------------------------------------------------
     ===============================================================================
     2 test cases selected
     
                    Sum   Critical   Non-critical
     FAILED   :       2          2              0

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 specialize the traits class template crpcut::match_traits for your predicate class, to provide a better suitable type, for example a specialization on the parameters.

[Note]Note
If you use GCC version 4.3 or higher, and compile your test sources with -std=c++0x, there is no limit to the number of parameters to the match<pred_type>() function nor the crpcut::match_traits specialization, otherwise there is a maximum limit of 9 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"  --------------------------------------------------------------
     samples/template-pred.cpp:84
     ASSERT_PRED(crpcut::match<is_substring>(needle), haystack)
       param1 = a mountain of hay
     for crpcut::match<is_substring>(needle): failed when searcing for steel
     
     -------------------------------------------------------------------------------
     ===============================================================================
     FAILED!: using_const_char_ptr
     phase="running"  --------------------------------------------------------------
     samples/template-pred.cpp:93
     ASSERT_PRED(crpcut::match<is_substring>(needle), haystack)
       param1 = a mountain of hay
     for crpcut::match<is_substring>(needle): failed when searcing for steel
     
     -------------------------------------------------------------------------------
     ===============================================================================
     FAILED!: using_string
     phase="running"  --------------------------------------------------------------
     samples/template-pred.cpp:102
     ASSERT_PRED(crpcut::match<is_substring>(needle), haystack)
       param1 = a mountain of hay
     for crpcut::match<is_substring>(needle): failed when searcing for steel
     
     -------------------------------------------------------------------------------
     ===============================================================================
     3 test cases selected
     
                    Sum   Critical   Non-critical
     FAILED   :       3          3              0

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.