// The test checks invokers specialized on a single attribute value type
BOOST_AUTO_TEST_CASE_TEMPLATE(single_type, CharT, char_types)
{
    typedef logging::basic_attribute_set< CharT > attr_set;
    typedef logging::basic_attribute_values_view< CharT > values_view;
    typedef test_data< CharT > data;

    attrs::constant< int > attr1(10);
    attrs::constant< double > attr2(5.5);
    attrs::constant< std::string > attr3("Hello, world!");

    attr_set set1, set2, set3;
    set1[data::attr1()] = attr1;
    set1[data::attr2()] = attr2;

    values_view view1(set1, set2, set3);
    view1.freeze();

    my_receiver recv;

    logging::value_visitor_invoker< CharT, int > invoker1(data::attr1());
    logging::value_visitor_invoker< CharT, double > invoker2(data::attr2());
    logging::value_visitor_invoker< CharT, std::string > invoker3(data::attr3());
    logging::value_visitor_invoker< CharT, char > invoker4(data::attr1());
    logging::value_visitor_invoker< CharT, int > invoker5(data::attr2());

    // These two extractors will find their values in the view
    recv.set_expected(10);
    BOOST_CHECK(invoker1(view1, recv));

    recv.set_expected(5.5);
    BOOST_CHECK(invoker2(view1, recv));

    // This one will not
    recv.set_expected();
    BOOST_CHECK(!invoker3(view1, recv));

    // But it will find it in this view
    set1[data::attr3()] = attr3;

    values_view view2(set1, set2, set3);
    view2.freeze();

    recv.set_expected("Hello, world!");
    BOOST_CHECK(invoker3(view2, recv));

    // This one will find the sought attribute value, but it will have an incorrect type
    recv.set_expected();
    BOOST_CHECK(!invoker4(view1, recv));

    // This one is the same, but there is a value of the requested type in the view
    BOOST_CHECK(!invoker5(view1, recv));
}
// The test checks invokers specialized with type lists
BOOST_AUTO_TEST_CASE_TEMPLATE(multiple_types, CharT, char_types)
{
    typedef logging::basic_attribute_set< CharT > attr_set;
    typedef logging::basic_attribute_values_view< CharT > values_view;
    typedef test_data< CharT > data;
    typedef mpl::vector< int, double, std::string, char >::type types;

    attrs::constant< int > attr1(10);
    attrs::constant< double > attr2(5.5);
    attrs::constant< std::string > attr3("Hello, world!");

    attr_set set1, set2, set3;
    set1[data::attr1()] = attr1;
    set1[data::attr2()] = attr2;

    values_view view1(set1, set2, set3);
    view1.freeze();

    my_receiver recv;

    logging::value_visitor_invoker< CharT, types > invoker1(data::attr1());
    logging::value_visitor_invoker< CharT, types > invoker2(data::attr2());
    logging::value_visitor_invoker< CharT, types > invoker3(data::attr3());

    // These two extractors will find their values in the view
    recv.set_expected(10);
    BOOST_CHECK(invoker1(view1, recv));

    recv.set_expected(5.5);
    BOOST_CHECK(invoker2(view1, recv));

    // This one will not
    recv.set_expected();
    BOOST_CHECK(!invoker3(view1, recv));

    // But it will find it in this view
    set1[data::attr3()] = attr3;

    values_view view2(set1, set2, set3);
    view2.freeze();

    recv.set_expected("Hello, world!");
    BOOST_CHECK(invoker3(view2, recv));
}
// TestInitialized
void
SendMessageTester::TestInitialized(SMTester &tester)
{
	// status_t SendMessage(uint32 command, BHandler *replyTo) const
	NextSubTest();
	{
		SMInvoker1 invoker1(false);
		SMInvoker1 invoker2(true);
		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
	}
	// status_t SendMessage(BMessage *message, BHandler *replyTo,
	//						bigtime_t timeout) const
	NextSubTest();
	{
// R5 crashes when passing a NULL message.
#ifndef TEST_R5
		SMInvoker2 invoker1(false, false, B_INFINITE_TIMEOUT);
		tester.Run(invoker1, 0, 0, B_BAD_VALUE, false, false, 0);
#endif
	}
	NextSubTest();
	{
		SMInvoker2 invoker1(true, false, B_INFINITE_TIMEOUT);
		SMInvoker2 invoker2(true, true, B_INFINITE_TIMEOUT);
		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
	}
	NextSubTest();
	{
		SMInvoker2 invoker1(true, false, 0);
		SMInvoker2 invoker2(true, true, 0);
		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
		tester.Run(invoker1, 20000, 0, B_WOULD_BLOCK, false, false, 0);
		tester.Run(invoker2, 20000, 0, B_WOULD_BLOCK, false, false, 0);
	}
	NextSubTest();
	{
		SMInvoker2 invoker1(true, false, 20000);
		SMInvoker2 invoker2(true, true, 20000);
		tester.Run(invoker1, 10000, 0, B_OK, true, false, 10000);
		tester.Run(invoker2, 10000, 0, B_OK, true, true, 10000);
		tester.Run(invoker1, 40000, 0, B_TIMED_OUT, false, false, 20000);
		tester.Run(invoker2, 40000, 0, B_TIMED_OUT, false, false, 20000);
	}
	// status_t SendMessage(BMessage *message, BMessenger replyTo,
	//						bigtime_t timeout) const
	NextSubTest();
	{
// R5 crashes when passing a NULL message.
#ifndef TEST_R5
		SMInvoker3 invoker1(false, false, B_INFINITE_TIMEOUT);
		tester.Run(invoker1, 0, 0, B_BAD_VALUE, false, false, 0);
#endif
	}
	NextSubTest();
	{
		SMInvoker3 invoker1(true, false, B_INFINITE_TIMEOUT);
		SMInvoker3 invoker2(true, true, B_INFINITE_TIMEOUT);
		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
	}
	NextSubTest();
	{
		SMInvoker3 invoker1(true, false, 0);
		SMInvoker3 invoker2(true, true, 0);
		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
		tester.Run(invoker1, 20000, 0, B_WOULD_BLOCK, false, false, 0);
		tester.Run(invoker2, 20000, 0, B_WOULD_BLOCK, false, false, 0);
	}
	NextSubTest();
	{
		SMInvoker3 invoker1(true, false, 20000);
		SMInvoker3 invoker2(true, true, 20000);
		tester.Run(invoker1, 10000, 0, B_OK, true, false, 10000);
		tester.Run(invoker2, 10000, 0, B_OK, true, true, 10000);
		tester.Run(invoker1, 40000, 0, B_TIMED_OUT, false, false, 20000);
		tester.Run(invoker2, 40000, 0, B_TIMED_OUT, false, false, 20000);
	}
	// status_t SendMessage(uint32 command, BMessage *reply) const
	NextSubTest();
	{
// R5 crashes when passing a NULL reply message
#ifndef TEST_R5
		SMInvoker4 invoker1(false);
#endif
		SMInvoker4 invoker2(true);
#ifndef TEST_R5
		tester.Run(invoker1, 20000, 20000, B_BAD_VALUE, false, false, 0);
#endif
		tester.Run(invoker2, 20000, 20000, B_OK, true, true, 40000);
	}
	// status_t SendMessage(BMessage *message, BMessage *reply,
	//						bigtime_t deliveryTimeout,
	//						bigtime_t replyTimeout) const
	NextSubTest();
	{
// R5 crashes when passing a NULL message.
#ifndef TEST_R5
		SMInvoker5 invoker1(false, true, B_INFINITE_TIMEOUT,
							B_INFINITE_TIMEOUT);
		tester.Run(invoker1, 0, 0, B_BAD_VALUE, false, false, 0);
#endif
	}
	NextSubTest();
	{
		SMInvoker5 invoker1(true, true, B_INFINITE_TIMEOUT,
							B_INFINITE_TIMEOUT);
		SMInvoker5 invoker2(true, true, B_INFINITE_TIMEOUT, 0);
		SMInvoker5 invoker3(true, true, B_INFINITE_TIMEOUT, 20000);
		tester.Run(invoker1, 0, 0, B_OK, true, true, 0);
		tester.Run(invoker1, 10000, 0, B_OK, true, true, 10000);
		tester.Run(invoker1, 0, 10000, B_OK, true, true, 10000);
		// These two are race-conditional: The sending task must be pre-empted
		// before reading from the reply port and the target must reply before
		// the sending task gets another time slice.
//		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
//		tester.Run(invoker2, 10000, 0, B_OK, true, true, 10000);
		tester.Run(invoker2, 0, 10000, B_WOULD_BLOCK, true, false, 0);
		tester.Run(invoker3, 0, 10000, B_OK, true, true, 10000);
		tester.Run(invoker3, 20000, 10000, B_OK, true, true, 30000);
		tester.Run(invoker3, 0, 30000, B_TIMED_OUT, true, false, 20000);
	}
	NextSubTest();
	{
		SMInvoker5 invoker1(true, true, 0, B_INFINITE_TIMEOUT);
		SMInvoker5 invoker2(true, true, 0, 0);
		SMInvoker5 invoker3(true, true, 0, 20000);
		tester.Run(invoker1, 0, 0, B_OK, true, true, 0);
		tester.Run(invoker1, 10000, 0, B_WOULD_BLOCK, false, false, 0);
		tester.Run(invoker1, 0, 10000, B_OK, true, true, 10000);
		// This one is race-conditional: The sending task must be pre-empted
		// before reading from the reply port and the target must reply before
		// the sending task gets another time slice.
//		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
		tester.Run(invoker2, 10000, 0, B_WOULD_BLOCK, false, false, 0);
		tester.Run(invoker2, 0, 10000, B_WOULD_BLOCK, true, false, 0);
		tester.Run(invoker3, 0, 10000, B_OK, true, true, 10000);
		tester.Run(invoker3, 10000, 10000, B_WOULD_BLOCK, false, false, 0);
		tester.Run(invoker3, 0, 30000, B_TIMED_OUT, true, false, 20000);
	}
	NextSubTest();
	{
		SMInvoker5 invoker1(true, true, 20000, B_INFINITE_TIMEOUT);
		SMInvoker5 invoker2(true, true, 20000, 0);
		SMInvoker5 invoker3(true, true, 20000, 20000);
		tester.Run(invoker1, 0, 0, B_OK, true, true, 0);
		tester.Run(invoker1, 10000, 0, B_OK, true, true, 10000);
		tester.Run(invoker1, 30000, 0, B_TIMED_OUT, false, false, 20000);
		tester.Run(invoker1, 10000, 20000, B_OK, true, true, 30000);
		// These two are race-conditional: The sending task must be pre-empted
		// before reading from the reply port and the target must reply before
		// the sending task gets another time slice.
//		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
//		tester.Run(invoker2, 10000, 0, B_OK, true, true, 0);
		tester.Run(invoker2, 30000, 0, B_TIMED_OUT, false, false, 20000);
		tester.Run(invoker2, 0, 10000, B_WOULD_BLOCK, true, false, 0);
		tester.Run(invoker3, 10000, 10000, B_OK, true, true, 20000);
		tester.Run(invoker3, 30000, 10000, B_TIMED_OUT, false, false, 20000);
		tester.Run(invoker3, 10000, 30000, B_TIMED_OUT, true, false, 30000);
	}
}