2 // Copyright Oliver Kowalke 2009.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
22 #include <boost/array.hpp>
23 #include <boost/assert.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <boost/test/unit_test.hpp>
26 #include <boost/utility.hpp>
27 #include <boost/variant.hpp>
29 #include <boost/context/fiber.hpp>
30 #include <boost/context/detail/config.hpp>
36 #if defined(BOOST_MSVC)
37 # pragma warning(push)
38 # pragma warning(disable: 4702 4723 4996)
41 typedef boost::variant
<int,std::string
> variant_t
;
43 namespace ctx
= boost::context
;
50 ctx::fiber
foo( ctx::fiber
&& f
, int i
) {
61 Y( Y
const&) = delete;
62 Y
& operator=( Y
const&) = delete;
84 moveable( moveable
&& other
) :
91 moveable
& operator=( moveable
&& other
) {
92 if ( this == & other
) return * this;
100 moveable( moveable
const& other
) = delete;
101 moveable
& operator=( moveable
const& other
) = delete;
108 struct my_exception
: public std::runtime_error
{
110 my_exception( ctx::fiber
&& f_
, char const* what
) :
111 std::runtime_error( what
),
112 f
{ std::move( f_
) } {
117 // Optimizations can remove the integer-divide-by-zero here.
118 #pragma optimize("", off)
119 void seh( bool & catched
) {
123 } __except( EXCEPTION_EXECUTE_HANDLER
) {
127 #pragma optimize("", on)
133 BOOST_CHECK_EQUAL( 0, value1
);
135 [&i
](ctx::fiber
&& f
) {
137 f
= std::move( f
).resume();
139 return std::move( f
);
141 f1
= std::move( f1
).resume();
142 BOOST_CHECK_EQUAL( 1, value1
);
150 f2
= std::move( f2
).resume();
151 BOOST_CHECK_EQUAL( 3, value1
);
159 ctx::fiber f
{ std::bind( & X::foo
, x
, std::placeholders::_1
, 7) };
160 f
= std::move( f
).resume();
161 BOOST_CHECK_EQUAL( 7, value1
);
164 void test_exception() {
166 const char * what
= "hello world";
168 [&what
](ctx::fiber
&& f
) {
170 throw std::runtime_error( what
);
171 } catch ( std::runtime_error
const& e
) {
174 return std::move( f
);
176 f
= std::move( f
).resume();
177 BOOST_CHECK_EQUAL( std::string( what
), value2
);
182 bool catched
= false;
183 std::thread([&catched
](){
184 ctx::fiber f
{ [&catched
](ctx::fiber
&& f
){
186 return std::move( f
);
189 f
= std::move( f
).resume();
191 BOOST_CHECK( catched
);
200 [&d
]( ctx::fiber
&& f
) {
203 return std::move( f
);
205 f
= std::move( f
).resume();
206 BOOST_CHECK_EQUAL( 10.58, value3
);
210 void test_stacked() {
214 [](ctx::fiber
&& f
) {
216 [](ctx::fiber
&& f
) {
218 return std::move( f
);
220 f1
= std::move( f1
).resume();
222 return std::move( f
);
224 f
= std::move( f
).resume();
225 BOOST_CHECK_EQUAL( 3, value1
);
226 BOOST_CHECK_EQUAL( 3.14, value3
);
230 void test_prealloc() {
232 ctx::default_stack alloc
;
233 ctx::stack_context
sctx( alloc
.allocate() );
234 void * sp
= static_cast< char * >( sctx
.sp
) - 10;
235 std::size_t size
= sctx
.size
- 10;
238 std::allocator_arg
, ctx::preallocated( sp
, size
, sctx
), alloc
,
239 [&i
]( ctx::fiber
&& f
) {
241 return std::move( f
);
243 f
= std::move( f
).resume();
244 BOOST_CHECK_EQUAL( 7, value1
);
251 ctx::fiber f
{ [&i
](ctx::fiber
&& f
) {
254 f
= std::move( f
).resume();
256 return std::move( f
);
258 f
= std::move( f
).resume();
259 f
= std::move( f
).resume_with(
260 [&i
](ctx::fiber
&& f
){
262 return std::move( f
);
265 BOOST_CHECK_EQUAL( i
, 200);
269 ctx::fiber f
{ [&f1
](ctx::fiber
&& f
) {
270 f
= std::move( f
).resume();
272 return std::move( f1
);
274 f
= std::move( f
).resume();
275 f
= std::move( f
).resume_with(
276 [&f1
](ctx::fiber
&& f
){
278 return std::move( f
);
283 void test_ontop_exception() {
286 ctx::fiber f
{ [](ctx::fiber
&& f
){
290 f
= std::move( f
).resume();
291 } catch ( my_exception
& ex
) {
293 return std::move( ex
.f
);
296 return std::move( f
);
298 f
= std::move( f
).resume();
299 BOOST_CHECK_EQUAL( 3, value1
);
300 const char * what
= "hello world";
301 f
= std::move( f
).resume_with(
302 [what
](ctx::fiber
&& f
){
303 throw my_exception( std::move( f
), what
);
304 return std::move( f
);
306 BOOST_CHECK_EQUAL( 3, value1
);
307 BOOST_CHECK_EQUAL( std::string( what
), value2
);
310 void test_termination() {
316 f
= std::move( f
).resume();
319 f
= std::move( f
).resume();
320 BOOST_CHECK_EQUAL( 3, value1
);
322 BOOST_CHECK_EQUAL( 7, value1
);
325 BOOST_CHECK_EQUAL( 0, value1
);
327 [](ctx::fiber
&& f
) {
329 return std::move( f
);
331 f
= std::move( f
).resume();
332 BOOST_CHECK_EQUAL( 3, value1
);
337 BOOST_CHECK_EQUAL( 0, value1
);
340 [&i
](ctx::fiber
&& f
){
342 f
= std::move( f
).resume();
344 return std::move( f
);
346 f
= std::move( f
).resume();
348 BOOST_CHECK_EQUAL( i
, value1
);
351 f
= std::move( f
).resume();
353 BOOST_CHECK_EQUAL( i
, value1
);
359 []( ctx::fiber
&& f
) {
363 sscanf("3.14 7.13", "%lf %lf", & n1
, & n2
);
364 BOOST_CHECK( n1
== 3.14);
365 BOOST_CHECK( n2
== 7.13);
370 sscanf("1 23", "%d %d", & n1
, & n2
);
371 BOOST_CHECK( n1
== 1);
372 BOOST_CHECK( n2
== 23);
377 sscanf("1 jjj 23", "%d %*[j] %d", & n1
, & n2
);
378 BOOST_CHECK( n1
== 1);
379 BOOST_CHECK( n2
== 23);
381 return std::move( f
);
385 void test_snprintf() {
387 []( ctx::fiber
&& f
) {
389 const char *fmt
= "sqrt(2) = %f";
391 snprintf( buf
, sizeof( buf
), fmt
, std::sqrt( 2) );
392 BOOST_CHECK( 0 < sizeof( buf
) );
393 BOOST_ASSERT( std::string("sqrt(2) = 1.41") == std::string( buf
, 14) );
396 std::uint64_t n
= 0xbcdef1234567890;
397 const char *fmt
= "0x%016llX";
399 snprintf( buf
, sizeof( buf
), fmt
, n
);
400 BOOST_ASSERT( std::string("0x0BCDEF1234567890") == std::string( buf
, 18) );
402 return std::move( f
);
407 void test_bug12215() {
409 [](ctx::fiber
&& f
) {
410 char buffer
[MAX_PATH
];
411 GetModuleFileName( nullptr, buffer
, MAX_PATH
);
412 return std::move( f
);
417 boost::unit_test::test_suite
* init_unit_test_suite( int, char* [])
419 boost::unit_test::test_suite
* test
=
420 BOOST_TEST_SUITE("Boost.Context: fiber test suite");
422 test
->add( BOOST_TEST_CASE( & test_move
) );
423 test
->add( BOOST_TEST_CASE( & test_bind
) );
424 test
->add( BOOST_TEST_CASE( & test_exception
) );
425 test
->add( BOOST_TEST_CASE( & test_fp
) );
426 test
->add( BOOST_TEST_CASE( & test_stacked
) );
427 test
->add( BOOST_TEST_CASE( & test_prealloc
) );
428 test
->add( BOOST_TEST_CASE( & test_ontop
) );
429 test
->add( BOOST_TEST_CASE( & test_ontop_exception
) );
430 test
->add( BOOST_TEST_CASE( & test_termination
) );
431 test
->add( BOOST_TEST_CASE( & test_sscanf
) );
432 test
->add( BOOST_TEST_CASE( & test_snprintf
) );
434 test
->add( BOOST_TEST_CASE( & test_bug12215
) );
440 #if defined(BOOST_MSVC)
441 # pragma warning(pop)