/* * test_signed_integer_output_with_karma -- Test case * exposing problem in Boost.Spirit.Karma's signed integer output * generators from Boost.Fusion adapted ADTs. * * Copyright (C) 2011 Torsten Maehne * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /*! * \file test_signed_integer_output_with_karma.cpp * * \brief Test signed integer output from Boost.Fusion adapted ADTs * and structs with Boost.Spirit.Karma rules. * * Boost.Spirit.Karma output rules should show the same behavior for * Boost.Fusion-adapted structs (direct access of the public member * variables) and ADTs (access to the private member variables via * getters and setters). This has been the case in Boost 1.44 and is * demonstrated in this test case for rational number ADTs and * structs, which use signed integer member variables. * * Compilation of this test case against Boost 1.45.0 and 1.46.1 will * fail. Compilation against Boost 1.47.0 and 1.48.0 will succeed, but * the output of negative values of signed integer members of * Boost.Fusion-adapted ADTs will be wrong. The minus sign is output * correctly, but it is followed by a wrong value, which seems to be * yielded by a cast from a signed to an unsigned integer value * instead of taking the absolute value of the signed integer * value. This has been observed on Mac OS X 10.7.2 (x86_64) with * Xcode 4.2 using Apple's g++ 4.2.1, Apple's clang++ * 3.0. Interestingly, compiling the test case against Boost 1.47.0 or * Boost 1.48.0 using MacPorts g++ 4.5.3, will yield more output * checks to fail for Boost.Fusion-adapted ADTs used in Karma output * rules. * * Compilation against Boost from the Subversion trunk (rev. 75505) * does only succeed using Apple's clang++ 3.0 and execution will * yield the same wrong output for negative values of signed integer * members of Boost.Fusion-adapted ADTs. Compilation fails with * Apple's g++ 4.2.1 and MacPorts g++ 4.5.3. * * \author Torsten Maehne * \date 2011-11-15 * \version $Id$ */ #define BOOST_TEST_MODULE test_signed_integer_output_with_karma #include #include #include #include #if BOOST_VERSION < 104500 // Until Boost 1.44 use BOOST_FUSION_ADAPT_CLASS #include #else // Since Boost 1.45 BOOST_FUSION_ADAPT_CLASS is named BOOST_FUSION_ADAPT_ADT #include #include #endif #include // Include only the strictly necessary parts of Boost.Spirit.Karma to reduce compile time. #include #include #include #include #include namespace { //! Rational number ADT with short integer members. typedef boost::rational rational_short_adt; //! Rational number struct with short integer members. struct rational_short_struct { short numerator, denominator; explicit rational_short_struct(short num = 0, short den = 1) : numerator(num), denominator(den) {} }; } // anonymous namespace #if BOOST_VERSION < 104500 // Adapt class boost::rational to a Fusion sequence. BOOST_FUSION_ADAPT_CLASS( ::rational_short_adt, (short, short, obj.numerator(), obj.numerator(val)) (short, short, obj.denominator(), obj.denominator(val)) ) #else // Adapt ADT boost::rational to a Fusion sequence. BOOST_FUSION_ADAPT_ADT( ::rational_short_adt, (short, short, obj.numerator(), obj.numerator(val)) (short, short, obj.denominator(), obj.denominator(val)) ) #endif // Adapt struct ::rational_short_struct to a Fusion sequence. BOOST_FUSION_ADAPT_STRUCT( ::rational_short_struct, (short, numerator) (short, denominator) ) namespace { //! Rational number ADT with signed integer members. typedef boost::rational rational_int_adt; //! Rational number struct with signed integer members. struct rational_int_struct { int numerator, denominator; explicit rational_int_struct(int num = 0, int den = 1) : numerator(num), denominator(den) {} }; } // anonymous namespace #if BOOST_VERSION < 104500 // Adapt class boost::rational to a Fusion sequence. BOOST_FUSION_ADAPT_CLASS( ::rational_int_adt, (int, int, obj.numerator(), obj.numerator(val)) (int, int, obj.denominator(), obj.denominator(val)) ) #else // Adapt ADT boost::rational to a Fusion sequence. BOOST_FUSION_ADAPT_ADT( ::rational_int_adt, (int, int, obj.numerator(), obj.numerator(val)) (int, int, obj.denominator(), obj.denominator(val)) ) #endif // Adapt struct ::rational_int_struct to a Fusion sequence. BOOST_FUSION_ADAPT_STRUCT( ::rational_int_struct, (int, numerator) (int, denominator) ) // rational ADT and struct with long integer members. namespace { //! Rational number ADT with long integer members. typedef boost::rational rational_long_adt; //! Rational number struct with long integer members. struct rational_long_struct { long numerator, denominator; explicit rational_long_struct(long num = 0, long den = 1) : numerator(num), denominator(den) {} }; } // anonymous namespace #if BOOST_VERSION < 104500 // Adapt class boost::rational to a Fusion sequence. BOOST_FUSION_ADAPT_CLASS( ::rational_long_adt, (long, long, obj.numerator(), obj.numerator(val)) (long, long, obj.denominator(), obj.denominator(val)) ) #else // Adapt ADT boost::rational to a Fusion sequence. BOOST_FUSION_ADAPT_ADT( ::rational_long_adt, (long, long, obj.numerator(), obj.numerator(val)) (long, long, obj.denominator(), obj.denominator(val)) ) #endif // Adapt struct ::rational_long_struct to a Fusion sequence. BOOST_FUSION_ADAPT_STRUCT( ::rational_long_struct, (long, numerator) (long, denominator) ) //! \test Test the output of Boost.Fusion-adapted ADTs with Karma rules. BOOST_AUTO_TEST_CASE(test_adapted_adt_output_with_karma) { // Namespace alias for Boost Spirit Karma. namespace karma = boost::spirit::karma; // Namespace alias for Boost Spirit Phoenix. namespace phx = boost::phoenix; using karma::short_; using karma::int_; using karma::long_; using boost::spirit::karma::generate; using boost::test_tools::output_test_stream; output_test_stream tout; typedef std::ostream_iterator tout_iter_type; // Output iterator type used as sink for the Boost.Spirit.Karma // generator to the output test stream. tout_iter_type tout_iter(tout); //! Check the Karma generator rules for ::rational_short_adt. karma::rule rational_short_adt_; rational_short_adt_.name("rational_short_adt_"); rational_short_adt_ = short_ << '/' << short_; BOOST_CHECK(generate(tout_iter, rational_short_adt_, rational_short_adt(1, 2))); BOOST_CHECK(tout.is_equal("1/2")); BOOST_CHECK(generate(tout_iter, rational_short_adt_, rational_short_adt(-1, 3))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_short_adt_, rational_short_adt(2, -6))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_short_adt_, rational_short_adt(-3, -12))); BOOST_CHECK(tout.is_equal("1/4")); //! Check the Karma generator rules for ::rational_int_adt. karma::rule rational_int_adt_; rational_int_adt_.name("rational_int_adt_"); rational_int_adt_ = int_ << '/' << int_; BOOST_CHECK(generate(tout_iter, rational_int_adt_, rational_int_adt(1, 2))); BOOST_CHECK(tout.is_equal("1/2")); BOOST_CHECK(generate(tout_iter, rational_int_adt_, rational_int_adt(-1, 3))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_int_adt_, rational_int_adt(2, -6))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_int_adt_, rational_int_adt(-3, -12))); BOOST_CHECK(tout.is_equal("1/4")); //! Check the Karma generator rules for ::rational_long_adt. karma::rule rational_long_adt_; rational_long_adt_.name("rational_long_adt_"); rational_long_adt_ = long_ << '/' << long_; BOOST_CHECK(generate(tout_iter, rational_long_adt_, rational_long_adt(1, 2))); BOOST_CHECK(tout.is_equal("1/2")); BOOST_CHECK(generate(tout_iter, rational_long_adt_, rational_long_adt(-1, 3))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_long_adt_, rational_long_adt(2, -6))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_long_adt_, rational_long_adt(-3, -12))); BOOST_CHECK(tout.is_equal("1/4")); } //! \test Test the output of Boost.Fusion-adapted structs with Karma rules. BOOST_AUTO_TEST_CASE(test_adapted_struct_output_with_karma) { // Namespace alias for Boost.Spirit.Karma. namespace karma = boost::spirit::karma; // Namespace alias for Boost.Spirit.Phoenix. namespace phx = boost::phoenix; using karma::short_; using karma::int_; using karma::long_; using boost::spirit::karma::generate; using boost::test_tools::output_test_stream; output_test_stream tout; typedef std::ostream_iterator tout_iter_type; // Output iterator type used as sink for the Boost.Spirit.Karma generator to the output test stream. tout_iter_type tout_iter(tout); //! Check the Karma generator rules for ::rational_short_struct. karma::rule rational_short_struct_; rational_short_struct_.name("rational_short_struct_"); rational_short_struct_ = short_ << '/' << short_; BOOST_CHECK(generate(tout_iter, rational_short_struct_, rational_short_struct(1, 3))); BOOST_CHECK(tout.is_equal("1/3")); BOOST_CHECK(generate(tout_iter, rational_short_struct_, rational_short_struct(-1, 3))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_short_struct_, rational_short_struct(1, -3))); BOOST_CHECK(tout.is_equal("1/-3")); BOOST_CHECK(generate(tout_iter, rational_short_struct_, rational_short_struct(-3, -12))); BOOST_CHECK(tout.is_equal("-3/-12")); //! Check the Karma generator rules for ::rational_int_struct. karma::rule rational_int_struct_; rational_int_struct_.name("rational_int_struct_"); rational_int_struct_ = int_ << '/' << int_; BOOST_CHECK(generate(tout_iter, rational_int_struct_, rational_int_struct(1, 3))); BOOST_CHECK(tout.is_equal("1/3")); BOOST_CHECK(generate(tout_iter, rational_int_struct_, rational_int_struct(-1, 3))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_int_struct_, rational_int_struct(1, -3))); BOOST_CHECK(tout.is_equal("1/-3")); BOOST_CHECK(generate(tout_iter, rational_int_struct_, rational_int_struct(-3, -12))); BOOST_CHECK(tout.is_equal("-3/-12")); //! Check the Karma generator rules for ::rational_long_struct. karma::rule rational_long_struct_; rational_long_struct_.name("rational_long_struct_"); rational_long_struct_ = long_ << '/' << long_; BOOST_CHECK(generate(tout_iter, rational_long_struct_, rational_long_struct(1, 3))); BOOST_CHECK(tout.is_equal("1/3")); BOOST_CHECK(generate(tout_iter, rational_long_struct_, rational_long_struct(-1, 3))); BOOST_CHECK(tout.is_equal("-1/3")); BOOST_CHECK(generate(tout_iter, rational_long_struct_, rational_long_struct(1, -3))); BOOST_CHECK(tout.is_equal("1/-3")); BOOST_CHECK(generate(tout_iter, rational_long_struct_, rational_long_struct(-3, -12))); BOOST_CHECK(tout.is_equal("-3/-12")); }