Ticket #6126: test_signed_integer_output_with_karma.cpp

File test_signed_integer_output_with_karma.cpp, 11.6 KB (added by t0rt1e@…, 11 years ago)

test case

Line 
1/*
2 * test_signed_integer_output_with_karma -- Test case
3 * exposing problem in Boost.Spirit.Karma's signed integer output
4 * generators from Boost.Fusion adapted ADTs.
5 *
6 * Copyright (C) 2011 Torsten Maehne
7 *
8 * Distributed under the Boost Software License, Version 1.0.
9 * (See accompanying file LICENSE_1_0.txt or copy at
10 * http://www.boost.org/LICENSE_1_0.txt)
11 */
12
13/*!
14 * \file test_signed_integer_output_with_karma.cpp
15 *
16 * \brief Test signed integer output from Boost.Fusion adapted ADTs
17 * and structs with Boost.Spirit.Karma rules.
18 *
19 * Boost.Spirit.Karma output rules should show the same behavior for
20 * Boost.Fusion-adapted structs (direct access of the public member
21 * variables) and ADTs (access to the private member variables via
22 * getters and setters). This has been the case in Boost 1.44 and is
23 * demonstrated in this test case for rational number ADTs and
24 * structs, which use signed integer member variables.
25 *
26 * Compilation of this test case against Boost 1.45.0 and 1.46.1 will
27 * fail. Compilation against Boost 1.47.0 and 1.48.0 will succeed, but
28 * the output of negative values of signed integer members of
29 * Boost.Fusion-adapted ADTs will be wrong. The minus sign is output
30 * correctly, but it is followed by a wrong value, which seems to be
31 * yielded by a cast from a signed to an unsigned integer value
32 * instead of taking the absolute value of the signed integer
33 * value. This has been observed on Mac OS X 10.7.2 (x86_64) with
34 * Xcode 4.2 using Apple's g++ 4.2.1, Apple's clang++
35 * 3.0. Interestingly, compiling the test case against Boost 1.47.0 or
36 * Boost 1.48.0 using MacPorts g++ 4.5.3, will yield more output
37 * checks to fail for Boost.Fusion-adapted ADTs used in Karma output
38 * rules.
39 *
40 * Compilation against Boost from the Subversion trunk (rev. 75505)
41 * does only succeed using Apple's clang++ 3.0 and execution will
42 * yield the same wrong output for negative values of signed integer
43 * members of Boost.Fusion-adapted ADTs. Compilation fails with
44 * Apple's g++ 4.2.1 and MacPorts g++ 4.5.3.
45 *
46 * \author Torsten Maehne
47 * \date 2011-11-15
48 * \version $Id$
49 */
50#define BOOST_TEST_MODULE test_signed_integer_output_with_karma
51#include <boost/test/included/unit_test.hpp>
52#include <boost/test/output_test_stream.hpp>
53#include <boost/rational.hpp>
54#include <boost/version.hpp>
55#if BOOST_VERSION < 104500
56// Until Boost 1.44 use BOOST_FUSION_ADAPT_CLASS
57#include <boost/fusion/include/adapt_class.hpp>
58#else
59// Since Boost 1.45 BOOST_FUSION_ADAPT_CLASS is named BOOST_FUSION_ADAPT_ADT
60#include <boost/fusion/include/adapt_adt.hpp>
61#include <boost/spirit/include/support_adapt_adt_attributes.hpp>
62#endif
63
64#include <boost/fusion/include/adapt_struct.hpp>
65// Include only the strictly necessary parts of Boost.Spirit.Karma to reduce compile time.
66#include <boost/spirit/include/karma_char.hpp>
67#include <boost/spirit/include/karma_nonterminal.hpp>
68#include <boost/spirit/include/karma_numeric.hpp>
69#include <boost/spirit/include/karma_operator.hpp>
70#include <boost/spirit/include/karma_generate.hpp>
71
72
73namespace {
74
75//! Rational number ADT with short integer members.
76typedef boost::rational<short> rational_short_adt;
77
78//! Rational number struct with short integer members.
79struct rational_short_struct {
80 short numerator, denominator;
81
82 explicit rational_short_struct(short num = 0, short den = 1)
83 : numerator(num), denominator(den)
84 {}
85};
86
87} // anonymous namespace
88
89#if BOOST_VERSION < 104500
90// Adapt class boost::rational<short> to a Fusion sequence.
91BOOST_FUSION_ADAPT_CLASS(
92 ::rational_short_adt,
93 (short, short, obj.numerator(), obj.numerator(val))
94 (short, short, obj.denominator(), obj.denominator(val))
95)
96#else
97// Adapt ADT boost::rational<short> to a Fusion sequence.
98BOOST_FUSION_ADAPT_ADT(
99 ::rational_short_adt,
100 (short, short, obj.numerator(), obj.numerator(val))
101 (short, short, obj.denominator(), obj.denominator(val))
102)
103#endif
104
105// Adapt struct ::rational_short_struct to a Fusion sequence.
106BOOST_FUSION_ADAPT_STRUCT(
107 ::rational_short_struct,
108 (short, numerator)
109 (short, denominator)
110)
111
112
113namespace {
114
115//! Rational number ADT with signed integer members.
116typedef boost::rational<int> rational_int_adt;
117
118//! Rational number struct with signed integer members.
119struct rational_int_struct {
120 int numerator, denominator;
121
122 explicit rational_int_struct(int num = 0, int den = 1)
123 : numerator(num), denominator(den)
124 {}
125};
126
127} // anonymous namespace
128
129#if BOOST_VERSION < 104500
130// Adapt class boost::rational<int> to a Fusion sequence.
131BOOST_FUSION_ADAPT_CLASS(
132 ::rational_int_adt,
133 (int, int, obj.numerator(), obj.numerator(val))
134 (int, int, obj.denominator(), obj.denominator(val))
135)
136#else
137// Adapt ADT boost::rational<int> to a Fusion sequence.
138BOOST_FUSION_ADAPT_ADT(
139 ::rational_int_adt,
140 (int, int, obj.numerator(), obj.numerator(val))
141 (int, int, obj.denominator(), obj.denominator(val))
142)
143#endif
144
145// Adapt struct ::rational_int_struct to a Fusion sequence.
146BOOST_FUSION_ADAPT_STRUCT(
147 ::rational_int_struct,
148 (int, numerator)
149 (int, denominator)
150)
151
152
153// rational ADT and struct with long integer members.
154namespace {
155
156//! Rational number ADT with long integer members.
157typedef boost::rational<long> rational_long_adt;
158
159//! Rational number struct with long integer members.
160struct rational_long_struct {
161 long numerator, denominator;
162
163 explicit rational_long_struct(long num = 0, long den = 1)
164 : numerator(num), denominator(den)
165 {}
166};
167
168} // anonymous namespace
169
170#if BOOST_VERSION < 104500
171// Adapt class boost::rational<long> to a Fusion sequence.
172BOOST_FUSION_ADAPT_CLASS(
173 ::rational_long_adt,
174 (long, long, obj.numerator(), obj.numerator(val))
175 (long, long, obj.denominator(), obj.denominator(val))
176)
177#else
178// Adapt ADT boost::rational<long> to a Fusion sequence.
179BOOST_FUSION_ADAPT_ADT(
180 ::rational_long_adt,
181 (long, long, obj.numerator(), obj.numerator(val))
182 (long, long, obj.denominator(), obj.denominator(val))
183)
184#endif
185
186// Adapt struct ::rational_long_struct to a Fusion sequence.
187BOOST_FUSION_ADAPT_STRUCT(
188 ::rational_long_struct,
189 (long, numerator)
190 (long, denominator)
191)
192
193
194//! \test Test the output of Boost.Fusion-adapted ADTs with Karma rules.
195BOOST_AUTO_TEST_CASE(test_adapted_adt_output_with_karma)
196{
197 // Namespace alias for Boost Spirit Karma.
198 namespace karma = boost::spirit::karma;
199 // Namespace alias for Boost Spirit Phoenix.
200 namespace phx = boost::phoenix;
201
202 using karma::short_;
203 using karma::int_;
204 using karma::long_;
205
206 using boost::spirit::karma::generate;
207
208 using boost::test_tools::output_test_stream;
209 output_test_stream tout;
210 typedef std::ostream_iterator<char> tout_iter_type;
211
212 // Output iterator type used as sink for the Boost.Spirit.Karma
213 // generator to the output test stream.
214 tout_iter_type tout_iter(tout);
215
216 //! Check the Karma generator rules for ::rational_short_adt.
217 karma::rule<tout_iter_type, rational_short_adt()> rational_short_adt_;
218 rational_short_adt_.name("rational_short_adt_");
219 rational_short_adt_ = short_ << '/' << short_;
220
221 BOOST_CHECK(generate(tout_iter, rational_short_adt_, rational_short_adt(1, 2)));
222 BOOST_CHECK(tout.is_equal("1/2"));
223
224 BOOST_CHECK(generate(tout_iter, rational_short_adt_, rational_short_adt(-1, 3)));
225 BOOST_CHECK(tout.is_equal("-1/3"));
226
227 BOOST_CHECK(generate(tout_iter, rational_short_adt_, rational_short_adt(2, -6)));
228 BOOST_CHECK(tout.is_equal("-1/3"));
229
230 BOOST_CHECK(generate(tout_iter, rational_short_adt_, rational_short_adt(-3, -12)));
231 BOOST_CHECK(tout.is_equal("1/4"));
232
233
234 //! Check the Karma generator rules for ::rational_int_adt.
235 karma::rule<tout_iter_type, rational_int_adt()> rational_int_adt_;
236 rational_int_adt_.name("rational_int_adt_");
237 rational_int_adt_ = int_ << '/' << int_;
238
239 BOOST_CHECK(generate(tout_iter, rational_int_adt_, rational_int_adt(1, 2)));
240 BOOST_CHECK(tout.is_equal("1/2"));
241
242 BOOST_CHECK(generate(tout_iter, rational_int_adt_, rational_int_adt(-1, 3)));
243 BOOST_CHECK(tout.is_equal("-1/3"));
244
245 BOOST_CHECK(generate(tout_iter, rational_int_adt_, rational_int_adt(2, -6)));
246 BOOST_CHECK(tout.is_equal("-1/3"));
247
248 BOOST_CHECK(generate(tout_iter, rational_int_adt_, rational_int_adt(-3, -12)));
249 BOOST_CHECK(tout.is_equal("1/4"));
250
251
252 //! Check the Karma generator rules for ::rational_long_adt.
253 karma::rule<tout_iter_type, rational_long_adt()> rational_long_adt_;
254 rational_long_adt_.name("rational_long_adt_");
255 rational_long_adt_ = long_ << '/' << long_;
256
257 BOOST_CHECK(generate(tout_iter, rational_long_adt_, rational_long_adt(1, 2)));
258 BOOST_CHECK(tout.is_equal("1/2"));
259
260 BOOST_CHECK(generate(tout_iter, rational_long_adt_, rational_long_adt(-1, 3)));
261 BOOST_CHECK(tout.is_equal("-1/3"));
262
263 BOOST_CHECK(generate(tout_iter, rational_long_adt_, rational_long_adt(2, -6)));
264 BOOST_CHECK(tout.is_equal("-1/3"));
265
266 BOOST_CHECK(generate(tout_iter, rational_long_adt_, rational_long_adt(-3, -12)));
267 BOOST_CHECK(tout.is_equal("1/4"));
268}
269
270
271//! \test Test the output of Boost.Fusion-adapted structs with Karma rules.
272BOOST_AUTO_TEST_CASE(test_adapted_struct_output_with_karma)
273{
274 // Namespace alias for Boost.Spirit.Karma.
275 namespace karma = boost::spirit::karma;
276 // Namespace alias for Boost.Spirit.Phoenix.
277 namespace phx = boost::phoenix;
278
279 using karma::short_;
280 using karma::int_;
281 using karma::long_;
282
283 using boost::spirit::karma::generate;
284
285 using boost::test_tools::output_test_stream;
286 output_test_stream tout;
287 typedef std::ostream_iterator<char> tout_iter_type;
288
289 // Output iterator type used as sink for the Boost.Spirit.Karma generator to the output test stream.
290 tout_iter_type tout_iter(tout);
291
292
293 //! Check the Karma generator rules for ::rational_short_struct.
294
295 karma::rule<tout_iter_type, rational_short_struct()> rational_short_struct_;
296 rational_short_struct_.name("rational_short_struct_");
297 rational_short_struct_ = short_ << '/' << short_;
298
299 BOOST_CHECK(generate(tout_iter, rational_short_struct_, rational_short_struct(1, 3)));
300 BOOST_CHECK(tout.is_equal("1/3"));
301
302 BOOST_CHECK(generate(tout_iter, rational_short_struct_, rational_short_struct(-1, 3)));
303 BOOST_CHECK(tout.is_equal("-1/3"));
304
305 BOOST_CHECK(generate(tout_iter, rational_short_struct_, rational_short_struct(1, -3)));
306 BOOST_CHECK(tout.is_equal("1/-3"));
307
308 BOOST_CHECK(generate(tout_iter, rational_short_struct_, rational_short_struct(-3, -12)));
309 BOOST_CHECK(tout.is_equal("-3/-12"));
310
311
312 //! Check the Karma generator rules for ::rational_int_struct.
313
314 karma::rule<tout_iter_type, rational_int_struct()> rational_int_struct_;
315 rational_int_struct_.name("rational_int_struct_");
316 rational_int_struct_ = int_ << '/' << int_;
317
318 BOOST_CHECK(generate(tout_iter, rational_int_struct_, rational_int_struct(1, 3)));
319 BOOST_CHECK(tout.is_equal("1/3"));
320
321 BOOST_CHECK(generate(tout_iter, rational_int_struct_, rational_int_struct(-1, 3)));
322 BOOST_CHECK(tout.is_equal("-1/3"));
323
324 BOOST_CHECK(generate(tout_iter, rational_int_struct_, rational_int_struct(1, -3)));
325 BOOST_CHECK(tout.is_equal("1/-3"));
326
327 BOOST_CHECK(generate(tout_iter, rational_int_struct_, rational_int_struct(-3, -12)));
328 BOOST_CHECK(tout.is_equal("-3/-12"));
329
330
331 //! Check the Karma generator rules for ::rational_long_struct.
332
333 karma::rule<tout_iter_type, rational_long_struct()> rational_long_struct_;
334 rational_long_struct_.name("rational_long_struct_");
335 rational_long_struct_ = long_ << '/' << long_;
336
337 BOOST_CHECK(generate(tout_iter, rational_long_struct_, rational_long_struct(1, 3)));
338 BOOST_CHECK(tout.is_equal("1/3"));
339
340 BOOST_CHECK(generate(tout_iter, rational_long_struct_, rational_long_struct(-1, 3)));
341 BOOST_CHECK(tout.is_equal("-1/3"));
342
343 BOOST_CHECK(generate(tout_iter, rational_long_struct_, rational_long_struct(1, -3)));
344 BOOST_CHECK(tout.is_equal("1/-3"));
345
346 BOOST_CHECK(generate(tout_iter, rational_long_struct_, rational_long_struct(-3, -12)));
347 BOOST_CHECK(tout.is_equal("-3/-12"));
348}