#include #include #include #include #include #include #include #include #include "Multimethod.hpp" #include "Holder.hpp" struct Timer { ~Timer() { std::cout << "Test time: " << timer_.elapsed() << " sec." << std::endl; std::cout << "Press any key" << std::endl; getchar(); }; boost::timer timer_; } timer; #define BOOST_TEST_MODULE Test #define BOOST_TEST_MAIN #include using namespace std; using namespace boost; using namespace unit_test; using namespace unit_test_framework; BOOST_AUTO_TEST_SUITE(TestHolder) // Multi method Sample namespace TestMultimethod { struct A {}; struct B {}; struct C { C() : n() {}; unsigned int n; }; struct D { D() : n() {}; unsigned int n; }; struct TestAnyMethod0 { // Multi method string operator()(any& arg1) { return Multimethod::apply(*this, arg1); }; string operator()(any& arg1, any& arg2) { return Multimethod::apply(*this, arg1, arg2); }; string operator()() const { return string("No argument"); }; string operator()(int value) const { return string("int"); }; string operator()(double value) const { return string("double"); }; string operator()(A value) const { return string("struct A"); }; string operator()(B& value) const { return string("struct B"); }; string operator()(const B& value) const { return string("struct B"); }; string operator()(C value) const { return lexical_cast(value.n++); }; string operator()(D& value) const { return lexical_cast(value.n++); }; string operator()(const D& value) const { return lexical_cast(value.n); }; string operator()(int value1, int value2) const { return string("int, int"); }; string operator()(int value1, double value2) const { return string("int, double"); }; string operator()(double value1, double value2) const { return string("double, double"); }; }; // "entry" Multi methods bool m01(Multimethod::entry()); bool m02(Multimethod::entry()); bool m03(Multimethod::entry()); bool m04(Multimethod::entry()); bool m05(Multimethod::entry()); bool m06(Multimethod::entry()); bool m07(Multimethod::entry()); bool m08(Multimethod::entry()); bool m09(Multimethod::entry()); bool m0a(Multimethod::entry()); bool a00(Multimethod::entry()); bool a01(Multimethod::entry()); bool a02(Multimethod::entry()); bool a03(Multimethod::entry()); bool a04(Multimethod::entry()); bool a05(Multimethod::entry()); bool a06(Multimethod::entry()); bool a07(Multimethod::entry()); bool a08(Multimethod::entry()); bool a09(Multimethod::entry()); bool a0a(Multimethod::entry()); BOOST_AUTO_TEST_CASE(test01) { TestAnyMethod0 m; any a(0); BOOST_CHECK_EQUAL(m(a), "int"); a = 0.0; BOOST_CHECK_EQUAL(m(a), "double"); a = A(); BOOST_CHECK_EQUAL(m(a), "struct A"); a = B(); BOOST_CHECK_EQUAL(m(a), "struct B"); any b(0); a = 0; BOOST_CHECK_EQUAL(m(a, b), "int, int"); b = 0.0; BOOST_CHECK_EQUAL(m(a, b), "int, double"); a = 0.0; BOOST_CHECK_EQUAL(m(a, b), "double, double"); a = C(); BOOST_CHECK_EQUAL(m(a), "0"); BOOST_CHECK_EQUAL(m(a), "0"); BOOST_CHECK_EQUAL(m(a), "0"); BOOST_CHECK_EQUAL(m(a), "0"); a = D(); BOOST_CHECK_EQUAL(m(a), "0"); BOOST_CHECK_EQUAL(m(a), "1"); BOOST_CHECK_EQUAL(m(a), "2"); BOOST_CHECK_EQUAL(m(a), "3"); } BOOST_AUTO_TEST_CASE(test02) { // You can use boost::any to hold multi method. // but you must use Multimethod::apply in this case. TestAnyMethod0 m0; any m(m0); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m)), "No argument"); any a(0); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "int"); a = 0.0; BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "double"); a = A(); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "struct A"); a = B(); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "struct B"); any b(0); a = 0; BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a, b)), "int, int"); b = 0.0; BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a, b)), "int, double"); a = 0.0; BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a, b)), "double, double"); a = C(); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "0"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "0"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "0"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "0"); a = D(); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "0"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "2"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "3"); } BOOST_AUTO_TEST_CASE(test03) { // You can also use not any classes to call multi methods. TestAnyMethod0 m0; any m(m0); any a(0); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "int"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, 1)), "int"); } struct TestAnyMethod1 { string operator()(any& arg1) { return Multimethod::apply(*this, arg1); }; string operator()(any& arg1, any& arg2) { return Multimethod::apply(*this, arg1, arg2); }; string operator()(int value) const { return string("1: int"); }; string operator()(double value) const { return string("1: double"); }; string operator()(A value) const { return string("1: struct A"); }; string operator()(B& value) const { return string("1: struct B"); }; string operator()(const B& value) const { return string("1: struct B"); }; string operator()(C value) const { return string("1: ") + lexical_cast(value.n++); }; string operator()(D& value) const { return string("1: ") + lexical_cast(value.n++); }; string operator()(const D& value) const { return string("1: ") + lexical_cast(value.n); }; string operator()(int value1, int value2) const { return string("1: int, int"); }; string operator()(int value1, double value2) const { return string("1: int, double"); }; string operator()(double value1, double value2) const { return string("1: double, double"); }; }; bool a10(Multimethod::entry()); bool a11(Multimethod::entry()); bool a12(Multimethod::entry()); bool a13(Multimethod::entry()); bool a14(Multimethod::entry()); bool a15(Multimethod::entry()); bool a16(Multimethod::entry()); bool a17(Multimethod::entry()); bool a18(Multimethod::entry()); BOOST_AUTO_TEST_CASE(test04) { // Return boost::any. TestAnyMethod1 m1; any m(m1); any a(0); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: int"); a = 0.0; BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: double"); a = A(); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: struct A"); a = B(); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: struct B"); any b(0); a = 0; BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a, b)), "1: int, int"); b = 0.0; BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a, b)), "1: int, double"); a = 0.0; BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a, b)), "1: double, double"); a = C(); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: 0"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: 0"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: 0"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: 0"); a = D(); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: 0"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: 1"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: 2"); BOOST_CHECK_EQUAL(any_cast(Multimethod::apply(m, a)), "1: 3"); }; } // Holder Sample namespace TestHolder { struct TestMethod0 { string operator()(Holder& arg1) { return Multimethod::apply(*this, arg1); }; string operator()(Holder& arg1, Holder& arg2) { return Multimethod::apply(*this, arg1, arg2); }; string operator()() const { return string("No argument"); }; string operator()(int value) const { return string("int0"); }; string operator()(double value) const { return string("double0"); }; string operator()(int arg1, int arg2) const { return string("int0, int0"); }; string operator()(int arg1, int arg2, int arg3) const { return string("string(int, int, int)"); }; }; // Entry for multi method bool tm00(Multimethod::entry()); bool tm01(Multimethod::entry()); bool tm02(Multimethod::entry()); bool tm03(Multimethod::entry()); bool tm04(Multimethod::entry()); // Entry for Holder's operator() bool htm00(Holder::entry()); bool htm01(Holder::entry()); bool htm02(Holder::entry()); bool htm03(Holder::entry()); bool htm04(Holder::entry()); bool htm05(Holder::entry()); BOOST_AUTO_TEST_CASE(test01) { // Multi method calling. TestMethod0 m; Holder h0(0); BOOST_CHECK_EQUAL(m(h0), "int0"); Holder h1(0.0); BOOST_CHECK_EQUAL(m(h1), "double0"); h1 = 0; BOOST_CHECK_EQUAL(m(h1), "int0"); BOOST_CHECK_EQUAL(m(h1, h1), "int0, int0"); h1 = 'a'; BOOST_CHECK_EQUAL(m(h1), "int0"); } struct TestMethod1 { string operator()(Holder& value) { return Multimethod::apply(*this, value); }; string operator()() const { return string("No argument"); }; string operator()(int value) const { return string("int1"); }; string operator()(double value) const { return string("double1"); }; }; // Entry for multi method bool tm10(Multimethod::entry()); bool tm11(Multimethod::entry()); bool tm12(Multimethod::entry()); bool tm13(Multimethod::entry()); // Entry for Holder's operator() bool htm10(Holder::entry()); bool htm11(Holder::entry()); bool htm12(Holder::entry()); bool htm13(Holder::entry()); BOOST_AUTO_TEST_CASE(test02) { TestMethod1 m; Holder h0(0); BOOST_CHECK_EQUAL(m(h0), "int1"); Holder h1(0.0); BOOST_CHECK_EQUAL(m(h1), "double1"); h1 = 0; BOOST_CHECK_EQUAL(m(h1), "int1"); h1 = 'a'; BOOST_CHECK_EQUAL(m(h1), "int1"); } struct TestVoidMethod { void operator()(Holder& value) { Multimethod::apply(*this, value); }; void operator()(int value) const { string("int"); }; void operator()(double value) const { string("double"); }; }; bool tvm1(Multimethod::entry()); bool tvm2(Multimethod::entry()); bool tvm3(Multimethod::entry()); bool htvm1(Holder::entry()); bool htvm2(Holder::entry()); bool htvm3(Holder::entry()); BOOST_AUTO_TEST_CASE(test03) { // void method calling. TestVoidMethod m; Holder h0(0); m(h0); } struct AA { AA() : val_() {}; unsigned int val_; }; struct BB { BB() : val_() {}; unsigned int val_; }; struct TestMethod2 { unsigned int operator()(Holder& value) { return Multimethod::apply(*this, value); }; unsigned int operator()(AA& value) const { return value.val_++; }; unsigned int operator()(const AA& value) const { return value.val_; }; unsigned int operator()(BB& value) const { return value.val_++; }; unsigned int operator()(const BB& value) const { return value.val_; }; }; bool tm21(Multimethod::entry()); bool tm22(Multimethod::entry()); bool htm21(Holder::entry()); bool htm22(Holder::entry()); BOOST_AUTO_TEST_CASE(test04) { TestMethod2 m; Holder a0((AA())); BOOST_CHECK_EQUAL(m(a0), 0); BOOST_CHECK_EQUAL(m(a0), 1); BOOST_CHECK_EQUAL(m(a0), 2); BOOST_CHECK_EQUAL(m(a0), 3); Holder b0((BB())); BOOST_CHECK_EQUAL(m(b0), 0); BOOST_CHECK_EQUAL(m(b0), 1); BOOST_CHECK_EQUAL(m(b0), 2); BOOST_CHECK_EQUAL(m(b0), 3); b0 = a0; // copy AA's instance to b0 BOOST_CHECK_EQUAL(m(b0), 4); BOOST_CHECK_EQUAL(m(b0), 5); BOOST_CHECK_EQUAL(m(b0), 6); BOOST_CHECK_EQUAL(m(b0), 7); } BOOST_AUTO_TEST_CASE(test05) { // you can Holder to hold multi method. Holder mm; mm = TestMethod0(); Holder h0(0); BOOST_CHECK_EQUAL(holder_cast(mm(h0)), "int0"); Holder h1(0.0); BOOST_CHECK_EQUAL(holder_cast(mm(h1)), "double0"); h1 = 0; BOOST_CHECK_EQUAL(holder_cast(mm(h1)), "int0"); BOOST_CHECK_EQUAL(holder_cast(mm(h1, h1)), "int0, int0"); BOOST_CHECK_EQUAL(holder_cast(mm(h1, h1, h1)), "string(int, int, int)"); h1 = 'a'; BOOST_CHECK_EQUAL(holder_cast(mm(h1)), "int0"); mm = TestMethod1(); // copy another multi method to mm. h0 = 0; BOOST_CHECK_EQUAL(holder_cast(mm(h0)), "int1"); h1 = 0.0; BOOST_CHECK_EQUAL(holder_cast(mm(h1)), "double1"); h1 = 0; BOOST_CHECK_EQUAL(holder_cast(mm(h1)), "int1"); h1 = 'a'; BOOST_CHECK_EQUAL(holder_cast(mm(h1)), "int1"); mm = TestVoidMethod(); // copy another void method to mm. h0 = 0; BOOST_CHECK_EQUAL(mm(h0).empty(), true); // return empty Holder. mm = TestMethod2(); Holder a0((AA())); BOOST_CHECK_EQUAL(holder_cast(mm(a0)), 0); BOOST_CHECK_EQUAL(holder_cast(mm(a0)), 1); BOOST_CHECK_EQUAL(holder_cast(mm(a0)), 2); BOOST_CHECK_EQUAL(holder_cast(mm(a0)), 3); Holder b0((BB())); BOOST_CHECK_EQUAL(holder_cast(mm(b0)), 0); BOOST_CHECK_EQUAL(holder_cast(mm(b0)), 1); BOOST_CHECK_EQUAL(holder_cast(mm(b0)), 2); BOOST_CHECK_EQUAL(holder_cast(mm(b0)), 3); BOOST_CHECK_EQUAL(holder_cast(mm(a0)), 4); BOOST_CHECK_EQUAL(holder_cast(mm(a0)), 5); BOOST_CHECK_EQUAL(holder_cast(mm(a0)), 6); BOOST_CHECK_EQUAL(holder_cast(mm(a0)), 7); } } namespace TestHolderConstruct { BOOST_AUTO_TEST_CASE(test) { // direct construction using https://svn.boost.org/trac/boost/ticket/2748 Holder h0; h0.reset(); BOOST_CHECK_EQUAL(holder_cast(h0), 0); h0.reset(); BOOST_CHECK_EQUAL(holder_cast(h0), 0.0); h0.reset >(); BOOST_CHECK_EQUAL(holder_cast >(h0).get(), static_cast(0)); h0.reset(1); BOOST_CHECK_EQUAL(holder_cast(h0), 1); h0.reset(1); BOOST_CHECK_EQUAL(holder_cast(h0), 1.0); h0.reset >(1, 2, 'a'); BOOST_CHECK_EQUAL((holder_cast >(h0).get<0>()), 1); BOOST_CHECK_EQUAL((holder_cast >(h0).get<1>()), 2.0); BOOST_CHECK_EQUAL((holder_cast >(h0).get<2>()), 'a'); } } BOOST_AUTO_TEST_SUITE_END()