emil-e / rapidcheck

QuickCheck clone for C++ with the goal of being simple to use with as little boilerplate as possible.
BSD 2-Clause "Simplified" License
1.01k stars 172 forks source link

Can't print values of structure even after overloading streaming operator #254

Open Makogan opened 4 years ago

Makogan commented 4 years ago

The gist of the problem is described in this stack overflow post: https://stackoverflow.com/users/6202327/makogan?tab=questions

I tried doing what the documentation specifies but my output is still <???> I was hoping I could find a solution here.

Thank you in advance.

bkrmendy commented 3 years ago

Please next time link the actual question instead of all your SO questions. The API for displaying is documented here: https://github.com/emil-e/rapidcheck/blob/master/doc/displaying.md

TL;DR: overload

std::ostream &operator<<(std::ostream &, const T &)

or

void showValue(const T &t, std::ostream &os)

ezzieyguywuf commented 3 years ago

I am having this same issue.

I can reproduce using the classify example by forcing one of the tests to fail with RC_ASSERT(false);, giving the following output:

Using configuration: seed=14471205679451365402

- RC_TAG
Falsifiable after 1 tests

std::tuple<User>:
(<???>)

/home/wolfie/Program/mycad-geometry/test/rapidcheck/examples/classify/main.cpp:31:
RC_ASSERT(false)

Expands to:
false

- RC_CLASSIFY
OK, passed 100 tests
 5.00% - user.username.empty()

Some of your RapidCheck properties had failures. To reproduce these, run with:
RC_PARAMS="reproduce=BYgUD9FVBdkGgB1ykzA1IrBYQtM5MQNyaAGULTODUjsGgB1ykzA1IHAABAAAAAAA"

Here is the diff against commit 718868c which produces this output:

--- a/examples/classify/main.cpp
+++ b/examples/classify/main.cpp
@@ -28,7 +28,7 @@ struct Arbitrary<User> {
 } // namespace rc

 int main() {
-  rc::check("RC_TAG", [](const User &user) { RC_TAG(user.gender); });
+  rc::check("RC_TAG", [](const User &user) { RC_TAG(user.gender); RC_ASSERT(false)});

   rc::check("RC_CLASSIFY",
             [](const User &user) { RC_CLASSIFY(user.username.empty()); });
ezzieyguywuf commented 3 years ago

After playing around with this a bit, I've learned the following: first, the classify example doesn't work simply because User did not have operator<< defined. This should probably be updated in order to provide a more fully working example.

More importantly, though, I learned that operator<< must be defined in the same namespace as the object you're define it for. e.g., this minimal example:

#include <rapidcheck.h>
#include <iostream>

namespace ns{
    struct Point {
        Point(){};
        Point(float x, float y, float z) : x(x), y(y), z(z){};
        float x, y, z;
    };
}

std::ostream& operator<< (std::ostream& os, const ns::Point& p)
{
    os << "(" << p.x << "," << p.y << ", " << p.z << ")";
    return os;
}

namespace rc{
    template<>
    struct Arbitrary<ns::Point> {
        static Gen<ns::Point> arbitrary() {
            return gen::build<ns::Point>(
                gen::set(&ns::Point::x),
                gen::set(&ns::Point::y),
                gen::set(&ns::Point::z)
            );
        }
    };
}

int main(void)
{
    ns::Point p(10, 20, 30);

    std::cout << "Hello point! " << p << std::endl;

    rc::check("workinG?",
              [](const ns::Point&){RC_ASSERT(false);});
}

Results in:

std::tuple<ns::Point>:
(<???>)

(among other output).

This is easily fixed with the following diff:

@@ -7,12 +7,12 @@
         Point(float x, float y, float z) : x(x), y(y), z(z){};
         float x, y, z;
     };
-}

-std::ostream& operator<< (std::ostream& os, const ns::Point& p)
-{
-    os << "(" << p.x << "," << p.y << ", " << p.z << ")";
-    return os;
+    std::ostream& operator<< (std::ostream& os, const ns::Point& p)
+    {
+        os << "(" << p.x << "," << p.y << ", " << p.z << ")";
+        return os;
+    }
 }