1 //
2 // read_until.cpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 // Disable autolinking for unit tests.
12 #if !defined(BOOST_ALL_NO_LIB)
13 #define BOOST_ALL_NO_LIB 1
14 #endif // !defined(BOOST_ALL_NO_LIB)
15 
16 // Test that header file is self-contained.
17 #include <boost/asio/read_until.hpp>
18 
19 #include <cstring>
20 #include "archetypes/async_result.hpp"
21 #include <boost/asio/io_service.hpp>
22 #include <boost/asio/streambuf.hpp>
23 #include "unit_test.hpp"
24 
25 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
26 # include <boost/bind.hpp>
27 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
28 # include <functional>
29 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
30 
31 class test_stream
32 {
33 public:
34   typedef boost::asio::io_service io_service_type;
35 
test_stream(boost::asio::io_service & io_service)36   test_stream(boost::asio::io_service& io_service)
37     : io_service_(io_service),
38       length_(0),
39       position_(0),
40       next_read_length_(0)
41   {
42   }
43 
get_io_service()44   io_service_type& get_io_service()
45   {
46     return io_service_;
47   }
48 
reset(const void * data,size_t length)49   void reset(const void* data, size_t length)
50   {
51     using namespace std; // For memcpy.
52 
53     BOOST_ASIO_CHECK(length <= max_length);
54 
55     memcpy(data_, data, length);
56     length_ = length;
57     position_ = 0;
58     next_read_length_ = length;
59   }
60 
next_read_length(size_t length)61   void next_read_length(size_t length)
62   {
63     next_read_length_ = length;
64   }
65 
66   template <typename Mutable_Buffers>
read_some(const Mutable_Buffers & buffers)67   size_t read_some(const Mutable_Buffers& buffers)
68   {
69     size_t n = boost::asio::buffer_copy(buffers,
70         boost::asio::buffer(data_, length_) + position_,
71         next_read_length_);
72     position_ += n;
73     return n;
74   }
75 
76   template <typename Mutable_Buffers>
read_some(const Mutable_Buffers & buffers,boost::system::error_code & ec)77   size_t read_some(const Mutable_Buffers& buffers,
78       boost::system::error_code& ec)
79   {
80     ec = boost::system::error_code();
81     return read_some(buffers);
82   }
83 
84   template <typename Mutable_Buffers, typename Handler>
async_read_some(const Mutable_Buffers & buffers,Handler handler)85   void async_read_some(const Mutable_Buffers& buffers, Handler handler)
86   {
87     size_t bytes_transferred = read_some(buffers);
88     io_service_.post(boost::asio::detail::bind_handler(
89           handler, boost::system::error_code(), bytes_transferred));
90   }
91 
92 private:
93   io_service_type& io_service_;
94   enum { max_length = 8192 };
95   char data_[max_length];
96   size_t length_;
97   size_t position_;
98   size_t next_read_length_;
99 };
100 
101 static const char read_data[]
102   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
103 
test_char_read_until()104 void test_char_read_until()
105 {
106   boost::asio::io_service ios;
107   test_stream s(ios);
108   boost::asio::streambuf sb1;
109   boost::asio::streambuf sb2(25);
110   boost::system::error_code ec;
111 
112   s.reset(read_data, sizeof(read_data));
113   sb1.consume(sb1.size());
114   std::size_t length = boost::asio::read_until(s, sb1, 'Z');
115   BOOST_ASIO_CHECK(length == 26);
116 
117   s.reset(read_data, sizeof(read_data));
118   s.next_read_length(1);
119   sb1.consume(sb1.size());
120   length = boost::asio::read_until(s, sb1, 'Z');
121   BOOST_ASIO_CHECK(length == 26);
122 
123   s.reset(read_data, sizeof(read_data));
124   s.next_read_length(10);
125   sb1.consume(sb1.size());
126   length = boost::asio::read_until(s, sb1, 'Z');
127   BOOST_ASIO_CHECK(length == 26);
128 
129   s.reset(read_data, sizeof(read_data));
130   sb1.consume(sb1.size());
131   length = boost::asio::read_until(s, sb1, 'Z', ec);
132   BOOST_ASIO_CHECK(!ec);
133   BOOST_ASIO_CHECK(length == 26);
134 
135   s.reset(read_data, sizeof(read_data));
136   s.next_read_length(1);
137   sb1.consume(sb1.size());
138   length = boost::asio::read_until(s, sb1, 'Z', ec);
139   BOOST_ASIO_CHECK(!ec);
140   BOOST_ASIO_CHECK(length == 26);
141 
142   s.reset(read_data, sizeof(read_data));
143   s.next_read_length(10);
144   sb1.consume(sb1.size());
145   length = boost::asio::read_until(s, sb1, 'Z', ec);
146   BOOST_ASIO_CHECK(!ec);
147   BOOST_ASIO_CHECK(length == 26);
148 
149   s.reset(read_data, sizeof(read_data));
150   sb2.consume(sb2.size());
151   length = boost::asio::read_until(s, sb2, 'Z', ec);
152   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
153   BOOST_ASIO_CHECK(length == 0);
154 
155   s.reset(read_data, sizeof(read_data));
156   s.next_read_length(1);
157   sb2.consume(sb2.size());
158   length = boost::asio::read_until(s, sb2, 'Z', ec);
159   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
160   BOOST_ASIO_CHECK(length == 0);
161 
162   s.reset(read_data, sizeof(read_data));
163   s.next_read_length(10);
164   sb2.consume(sb2.size());
165   length = boost::asio::read_until(s, sb2, 'Z', ec);
166   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
167   BOOST_ASIO_CHECK(length == 0);
168 
169   s.reset(read_data, sizeof(read_data));
170   sb2.consume(sb2.size());
171   length = boost::asio::read_until(s, sb2, 'Y', ec);
172   BOOST_ASIO_CHECK(!ec);
173   BOOST_ASIO_CHECK(length == 25);
174 
175   s.reset(read_data, sizeof(read_data));
176   s.next_read_length(1);
177   sb2.consume(sb2.size());
178   length = boost::asio::read_until(s, sb2, 'Y', ec);
179   BOOST_ASIO_CHECK(!ec);
180   BOOST_ASIO_CHECK(length == 25);
181 
182   s.reset(read_data, sizeof(read_data));
183   s.next_read_length(10);
184   sb2.consume(sb2.size());
185   length = boost::asio::read_until(s, sb2, 'Y', ec);
186   BOOST_ASIO_CHECK(!ec);
187   BOOST_ASIO_CHECK(length == 25);
188 }
189 
test_string_read_until()190 void test_string_read_until()
191 {
192   boost::asio::io_service ios;
193   test_stream s(ios);
194   boost::asio::streambuf sb1;
195   boost::asio::streambuf sb2(25);
196   boost::system::error_code ec;
197 
198   s.reset(read_data, sizeof(read_data));
199   sb1.consume(sb1.size());
200   std::size_t length = boost::asio::read_until(s, sb1, "XYZ");
201   BOOST_ASIO_CHECK(length == 26);
202 
203   s.reset(read_data, sizeof(read_data));
204   s.next_read_length(1);
205   sb1.consume(sb1.size());
206   length = boost::asio::read_until(s, sb1, "XYZ");
207   BOOST_ASIO_CHECK(length == 26);
208 
209   s.reset(read_data, sizeof(read_data));
210   s.next_read_length(10);
211   sb1.consume(sb1.size());
212   length = boost::asio::read_until(s, sb1, "XYZ");
213   BOOST_ASIO_CHECK(length == 26);
214 
215   s.reset(read_data, sizeof(read_data));
216   sb1.consume(sb1.size());
217   length = boost::asio::read_until(s, sb1, "XYZ", ec);
218   BOOST_ASIO_CHECK(!ec);
219   BOOST_ASIO_CHECK(length == 26);
220 
221   s.reset(read_data, sizeof(read_data));
222   s.next_read_length(1);
223   sb1.consume(sb1.size());
224   length = boost::asio::read_until(s, sb1, "XYZ", ec);
225   BOOST_ASIO_CHECK(!ec);
226   BOOST_ASIO_CHECK(length == 26);
227 
228   s.reset(read_data, sizeof(read_data));
229   s.next_read_length(10);
230   sb1.consume(sb1.size());
231   length = boost::asio::read_until(s, sb1, "XYZ", ec);
232   BOOST_ASIO_CHECK(!ec);
233   BOOST_ASIO_CHECK(length == 26);
234 
235   s.reset(read_data, sizeof(read_data));
236   sb2.consume(sb2.size());
237   length = boost::asio::read_until(s, sb2, "XYZ", ec);
238   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
239   BOOST_ASIO_CHECK(length == 0);
240 
241   s.reset(read_data, sizeof(read_data));
242   s.next_read_length(1);
243   sb2.consume(sb2.size());
244   length = boost::asio::read_until(s, sb2, "XYZ", ec);
245   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
246   BOOST_ASIO_CHECK(length == 0);
247 
248   s.reset(read_data, sizeof(read_data));
249   s.next_read_length(10);
250   sb2.consume(sb2.size());
251   length = boost::asio::read_until(s, sb2, "XYZ", ec);
252   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
253   BOOST_ASIO_CHECK(length == 0);
254 
255   s.reset(read_data, sizeof(read_data));
256   sb2.consume(sb2.size());
257   length = boost::asio::read_until(s, sb2, "WXY", ec);
258   BOOST_ASIO_CHECK(!ec);
259   BOOST_ASIO_CHECK(length == 25);
260 
261   s.reset(read_data, sizeof(read_data));
262   s.next_read_length(1);
263   sb2.consume(sb2.size());
264   length = boost::asio::read_until(s, sb2, "WXY", ec);
265   BOOST_ASIO_CHECK(!ec);
266   BOOST_ASIO_CHECK(length == 25);
267 
268   s.reset(read_data, sizeof(read_data));
269   s.next_read_length(10);
270   sb2.consume(sb2.size());
271   length = boost::asio::read_until(s, sb2, "WXY", ec);
272   BOOST_ASIO_CHECK(!ec);
273   BOOST_ASIO_CHECK(length == 25);
274 }
275 
276 class match_char
277 {
278 public:
match_char(char c)279   explicit match_char(char c) : c_(c) {}
280 
281   template <typename Iterator>
operator ()(Iterator begin,Iterator end) const282   std::pair<Iterator, bool> operator()(
283       Iterator begin, Iterator end) const
284   {
285     Iterator i = begin;
286     while (i != end)
287       if (c_ == *i++)
288         return std::make_pair(i, true);
289     return std::make_pair(i, false);
290   }
291 
292 private:
293   char c_;
294 };
295 
296 namespace boost {
297 namespace asio {
298   template <> struct is_match_condition<match_char>
299   {
300     enum { value = true };
301   };
302 } // namespace asio
303 } // namespace boost
304 
test_match_condition_read_until()305 void test_match_condition_read_until()
306 {
307   boost::asio::io_service ios;
308   test_stream s(ios);
309   boost::asio::streambuf sb1;
310   boost::asio::streambuf sb2(25);
311   boost::system::error_code ec;
312 
313   s.reset(read_data, sizeof(read_data));
314   sb1.consume(sb1.size());
315   std::size_t length = boost::asio::read_until(s, sb1, match_char('Z'));
316   BOOST_ASIO_CHECK(length == 26);
317 
318   s.reset(read_data, sizeof(read_data));
319   s.next_read_length(1);
320   sb1.consume(sb1.size());
321   length = boost::asio::read_until(s, sb1, match_char('Z'));
322   BOOST_ASIO_CHECK(length == 26);
323 
324   s.reset(read_data, sizeof(read_data));
325   s.next_read_length(10);
326   sb1.consume(sb1.size());
327   length = boost::asio::read_until(s, sb1, match_char('Z'));
328   BOOST_ASIO_CHECK(length == 26);
329 
330   s.reset(read_data, sizeof(read_data));
331   sb1.consume(sb1.size());
332   length = boost::asio::read_until(s, sb1, match_char('Z'), ec);
333   BOOST_ASIO_CHECK(!ec);
334   BOOST_ASIO_CHECK(length == 26);
335 
336   s.reset(read_data, sizeof(read_data));
337   s.next_read_length(1);
338   sb1.consume(sb1.size());
339   length = boost::asio::read_until(s, sb1, match_char('Z'), ec);
340   BOOST_ASIO_CHECK(!ec);
341   BOOST_ASIO_CHECK(length == 26);
342 
343   s.reset(read_data, sizeof(read_data));
344   s.next_read_length(10);
345   sb1.consume(sb1.size());
346   length = boost::asio::read_until(s, sb1, match_char('Z'), ec);
347   BOOST_ASIO_CHECK(!ec);
348   BOOST_ASIO_CHECK(length == 26);
349 
350   s.reset(read_data, sizeof(read_data));
351   sb2.consume(sb2.size());
352   length = boost::asio::read_until(s, sb2, match_char('Z'), ec);
353   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
354   BOOST_ASIO_CHECK(length == 0);
355 
356   s.reset(read_data, sizeof(read_data));
357   s.next_read_length(1);
358   sb2.consume(sb2.size());
359   length = boost::asio::read_until(s, sb2, match_char('Z'), ec);
360   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
361   BOOST_ASIO_CHECK(length == 0);
362 
363   s.reset(read_data, sizeof(read_data));
364   s.next_read_length(10);
365   sb2.consume(sb2.size());
366   length = boost::asio::read_until(s, sb2, match_char('Z'), ec);
367   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
368   BOOST_ASIO_CHECK(length == 0);
369 
370   s.reset(read_data, sizeof(read_data));
371   sb2.consume(sb2.size());
372   length = boost::asio::read_until(s, sb2, match_char('Y'), ec);
373   BOOST_ASIO_CHECK(!ec);
374   BOOST_ASIO_CHECK(length == 25);
375 
376   s.reset(read_data, sizeof(read_data));
377   s.next_read_length(1);
378   sb2.consume(sb2.size());
379   length = boost::asio::read_until(s, sb2, match_char('Y'), ec);
380   BOOST_ASIO_CHECK(!ec);
381   BOOST_ASIO_CHECK(length == 25);
382 
383   s.reset(read_data, sizeof(read_data));
384   s.next_read_length(10);
385   sb2.consume(sb2.size());
386   length = boost::asio::read_until(s, sb2, match_char('Y'), ec);
387   BOOST_ASIO_CHECK(!ec);
388   BOOST_ASIO_CHECK(length == 25);
389 }
390 
async_read_handler(const boost::system::error_code & err,boost::system::error_code * err_out,std::size_t bytes_transferred,std::size_t * bytes_out,bool * called)391 void async_read_handler(
392     const boost::system::error_code& err, boost::system::error_code* err_out,
393     std::size_t bytes_transferred, std::size_t* bytes_out, bool* called)
394 {
395   *err_out = err;
396   *bytes_out = bytes_transferred;
397   *called = true;
398 }
399 
test_char_async_read_until()400 void test_char_async_read_until()
401 {
402 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
403   namespace bindns = boost;
404 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
405   namespace bindns = std;
406   using std::placeholders::_1;
407   using std::placeholders::_2;
408 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
409 
410   boost::asio::io_service ios;
411   test_stream s(ios);
412   boost::asio::streambuf sb1;
413   boost::asio::streambuf sb2(25);
414   boost::system::error_code ec;
415   std::size_t length;
416   bool called;
417 
418   s.reset(read_data, sizeof(read_data));
419   ec = boost::system::error_code();
420   length = 0;
421   called = false;
422   sb1.consume(sb1.size());
423   boost::asio::async_read_until(s, sb1, 'Z',
424       bindns::bind(async_read_handler, _1, &ec,
425         _2, &length, &called));
426   ios.reset();
427   ios.run();
428   BOOST_ASIO_CHECK(called);
429   BOOST_ASIO_CHECK(!ec);
430   BOOST_ASIO_CHECK(length == 26);
431 
432   s.reset(read_data, sizeof(read_data));
433   s.next_read_length(1);
434   ec = boost::system::error_code();
435   length = 0;
436   called = false;
437   sb1.consume(sb1.size());
438   boost::asio::async_read_until(s, sb1, 'Z',
439       bindns::bind(async_read_handler, _1, &ec,
440         _2, &length, &called));
441   ios.reset();
442   ios.run();
443   BOOST_ASIO_CHECK(called);
444   BOOST_ASIO_CHECK(!ec);
445   BOOST_ASIO_CHECK(length == 26);
446 
447   s.reset(read_data, sizeof(read_data));
448   s.next_read_length(10);
449   ec = boost::system::error_code();
450   length = 0;
451   called = false;
452   sb1.consume(sb1.size());
453   boost::asio::async_read_until(s, sb1, 'Z',
454       bindns::bind(async_read_handler, _1, &ec,
455         _2, &length, &called));
456   ios.reset();
457   ios.run();
458   BOOST_ASIO_CHECK(called);
459   BOOST_ASIO_CHECK(!ec);
460   BOOST_ASIO_CHECK(length == 26);
461 
462   s.reset(read_data, sizeof(read_data));
463   ec = boost::system::error_code();
464   length = 0;
465   called = false;
466   sb2.consume(sb2.size());
467   boost::asio::async_read_until(s, sb2, 'Z',
468       bindns::bind(async_read_handler, _1, &ec,
469         _2, &length, &called));
470   ios.reset();
471   ios.run();
472   BOOST_ASIO_CHECK(called);
473   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
474   BOOST_ASIO_CHECK(length == 0);
475 
476   s.reset(read_data, sizeof(read_data));
477   s.next_read_length(1);
478   ec = boost::system::error_code();
479   length = 0;
480   called = false;
481   sb2.consume(sb2.size());
482   boost::asio::async_read_until(s, sb2, 'Z',
483       bindns::bind(async_read_handler, _1, &ec,
484         _2, &length, &called));
485   ios.reset();
486   ios.run();
487   BOOST_ASIO_CHECK(called);
488   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
489   BOOST_ASIO_CHECK(length == 0);
490 
491   s.reset(read_data, sizeof(read_data));
492   s.next_read_length(10);
493   ec = boost::system::error_code();
494   length = 0;
495   called = false;
496   sb2.consume(sb2.size());
497   boost::asio::async_read_until(s, sb2, 'Z',
498       bindns::bind(async_read_handler, _1, &ec,
499         _2, &length, &called));
500   ios.reset();
501   ios.run();
502   BOOST_ASIO_CHECK(called);
503   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
504   BOOST_ASIO_CHECK(length == 0);
505 
506   s.reset(read_data, sizeof(read_data));
507   ec = boost::system::error_code();
508   length = 0;
509   called = false;
510   sb2.consume(sb2.size());
511   boost::asio::async_read_until(s, sb2, 'Y',
512       bindns::bind(async_read_handler, _1, &ec,
513         _2, &length, &called));
514   ios.reset();
515   ios.run();
516   BOOST_ASIO_CHECK(called);
517   BOOST_ASIO_CHECK(!ec);
518   BOOST_ASIO_CHECK(length == 25);
519 
520   s.reset(read_data, sizeof(read_data));
521   s.next_read_length(1);
522   ec = boost::system::error_code();
523   length = 0;
524   called = false;
525   sb2.consume(sb2.size());
526   boost::asio::async_read_until(s, sb2, 'Y',
527       bindns::bind(async_read_handler, _1, &ec,
528         _2, &length, &called));
529   ios.reset();
530   ios.run();
531   BOOST_ASIO_CHECK(called);
532   BOOST_ASIO_CHECK(!ec);
533   BOOST_ASIO_CHECK(length == 25);
534 
535   s.reset(read_data, sizeof(read_data));
536   s.next_read_length(10);
537   ec = boost::system::error_code();
538   length = 0;
539   called = false;
540   sb2.consume(sb2.size());
541   boost::asio::async_read_until(s, sb2, 'Y',
542       bindns::bind(async_read_handler, _1, &ec,
543         _2, &length, &called));
544   ios.reset();
545   ios.run();
546   BOOST_ASIO_CHECK(called);
547   BOOST_ASIO_CHECK(!ec);
548   BOOST_ASIO_CHECK(length == 25);
549 
550   s.reset(read_data, sizeof(read_data));
551   sb2.consume(sb2.size());
552   int i = boost::asio::async_read_until(s, sb2, 'Y',
553       archetypes::lazy_handler());
554   BOOST_ASIO_CHECK(i == 42);
555   ios.reset();
556   ios.run();
557 }
558 
test_string_async_read_until()559 void test_string_async_read_until()
560 {
561 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
562   namespace bindns = boost;
563 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
564   namespace bindns = std;
565   using std::placeholders::_1;
566   using std::placeholders::_2;
567 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
568 
569   boost::asio::io_service ios;
570   test_stream s(ios);
571   boost::asio::streambuf sb1;
572   boost::asio::streambuf sb2(25);
573   boost::system::error_code ec;
574   std::size_t length;
575   bool called;
576 
577   s.reset(read_data, sizeof(read_data));
578   ec = boost::system::error_code();
579   length = 0;
580   called = false;
581   sb1.consume(sb1.size());
582   boost::asio::async_read_until(s, sb1, "XYZ",
583       bindns::bind(async_read_handler, _1, &ec,
584         _2, &length, &called));
585   ios.reset();
586   ios.run();
587   BOOST_ASIO_CHECK(called);
588   BOOST_ASIO_CHECK(!ec);
589   BOOST_ASIO_CHECK(length == 26);
590 
591   s.reset(read_data, sizeof(read_data));
592   s.next_read_length(1);
593   ec = boost::system::error_code();
594   length = 0;
595   called = false;
596   sb1.consume(sb1.size());
597   boost::asio::async_read_until(s, sb1, "XYZ",
598       bindns::bind(async_read_handler, _1, &ec,
599         _2, &length, &called));
600   ios.reset();
601   ios.run();
602   BOOST_ASIO_CHECK(called);
603   BOOST_ASIO_CHECK(!ec);
604   BOOST_ASIO_CHECK(length == 26);
605 
606   s.reset(read_data, sizeof(read_data));
607   s.next_read_length(10);
608   ec = boost::system::error_code();
609   length = 0;
610   called = false;
611   sb1.consume(sb1.size());
612   boost::asio::async_read_until(s, sb1, "XYZ",
613       bindns::bind(async_read_handler, _1, &ec,
614         _2, &length, &called));
615   ios.reset();
616   ios.run();
617   BOOST_ASIO_CHECK(called);
618   BOOST_ASIO_CHECK(!ec);
619   BOOST_ASIO_CHECK(length == 26);
620 
621   s.reset(read_data, sizeof(read_data));
622   ec = boost::system::error_code();
623   length = 0;
624   called = false;
625   sb2.consume(sb2.size());
626   boost::asio::async_read_until(s, sb2, "XYZ",
627       bindns::bind(async_read_handler, _1, &ec,
628         _2, &length, &called));
629   ios.reset();
630   ios.run();
631   BOOST_ASIO_CHECK(called);
632   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
633   BOOST_ASIO_CHECK(length == 0);
634 
635   s.reset(read_data, sizeof(read_data));
636   s.next_read_length(1);
637   ec = boost::system::error_code();
638   length = 0;
639   called = false;
640   sb2.consume(sb2.size());
641   boost::asio::async_read_until(s, sb2, "XYZ",
642       bindns::bind(async_read_handler, _1, &ec,
643         _2, &length, &called));
644   ios.reset();
645   ios.run();
646   BOOST_ASIO_CHECK(called);
647   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
648   BOOST_ASIO_CHECK(length == 0);
649 
650   s.reset(read_data, sizeof(read_data));
651   s.next_read_length(10);
652   ec = boost::system::error_code();
653   length = 0;
654   called = false;
655   sb2.consume(sb2.size());
656   boost::asio::async_read_until(s, sb2, "XYZ",
657       bindns::bind(async_read_handler, _1, &ec,
658         _2, &length, &called));
659   ios.reset();
660   ios.run();
661   BOOST_ASIO_CHECK(called);
662   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
663   BOOST_ASIO_CHECK(length == 0);
664 
665   s.reset(read_data, sizeof(read_data));
666   ec = boost::system::error_code();
667   length = 0;
668   called = false;
669   sb2.consume(sb2.size());
670   boost::asio::async_read_until(s, sb2, "WXY",
671       bindns::bind(async_read_handler, _1, &ec,
672         _2, &length, &called));
673   ios.reset();
674   ios.run();
675   BOOST_ASIO_CHECK(called);
676   BOOST_ASIO_CHECK(!ec);
677   BOOST_ASIO_CHECK(length == 25);
678 
679   s.reset(read_data, sizeof(read_data));
680   s.next_read_length(1);
681   ec = boost::system::error_code();
682   length = 0;
683   called = false;
684   sb2.consume(sb2.size());
685   boost::asio::async_read_until(s, sb2, "WXY",
686       bindns::bind(async_read_handler, _1, &ec,
687         _2, &length, &called));
688   ios.reset();
689   ios.run();
690   BOOST_ASIO_CHECK(called);
691   BOOST_ASIO_CHECK(!ec);
692   BOOST_ASIO_CHECK(length == 25);
693 
694   s.reset(read_data, sizeof(read_data));
695   s.next_read_length(10);
696   ec = boost::system::error_code();
697   length = 0;
698   called = false;
699   sb2.consume(sb2.size());
700   boost::asio::async_read_until(s, sb2, "WXY",
701       bindns::bind(async_read_handler, _1, &ec,
702         _2, &length, &called));
703   ios.reset();
704   ios.run();
705   BOOST_ASIO_CHECK(called);
706   BOOST_ASIO_CHECK(!ec);
707   BOOST_ASIO_CHECK(length == 25);
708 
709   s.reset(read_data, sizeof(read_data));
710   sb2.consume(sb2.size());
711   int i = boost::asio::async_read_until(s, sb2, "WXY",
712       archetypes::lazy_handler());
713   BOOST_ASIO_CHECK(i == 42);
714   ios.reset();
715   ios.run();
716 }
717 
test_match_condition_async_read_until()718 void test_match_condition_async_read_until()
719 {
720 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
721   namespace bindns = boost;
722 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
723   namespace bindns = std;
724   using std::placeholders::_1;
725   using std::placeholders::_2;
726 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
727 
728   boost::asio::io_service ios;
729   test_stream s(ios);
730   boost::asio::streambuf sb1;
731   boost::asio::streambuf sb2(25);
732   boost::system::error_code ec;
733   std::size_t length;
734   bool called;
735 
736   s.reset(read_data, sizeof(read_data));
737   ec = boost::system::error_code();
738   length = 0;
739   called = false;
740   sb1.consume(sb1.size());
741   boost::asio::async_read_until(s, sb1, match_char('Z'),
742       bindns::bind(async_read_handler, _1, &ec,
743         _2, &length, &called));
744   ios.reset();
745   ios.run();
746   BOOST_ASIO_CHECK(called);
747   BOOST_ASIO_CHECK(!ec);
748   BOOST_ASIO_CHECK(length == 26);
749 
750   s.reset(read_data, sizeof(read_data));
751   s.next_read_length(1);
752   ec = boost::system::error_code();
753   length = 0;
754   called = false;
755   sb1.consume(sb1.size());
756   boost::asio::async_read_until(s, sb1, match_char('Z'),
757       bindns::bind(async_read_handler, _1, &ec,
758         _2, &length, &called));
759   ios.reset();
760   ios.run();
761   BOOST_ASIO_CHECK(called);
762   BOOST_ASIO_CHECK(!ec);
763   BOOST_ASIO_CHECK(length == 26);
764 
765   s.reset(read_data, sizeof(read_data));
766   s.next_read_length(10);
767   ec = boost::system::error_code();
768   length = 0;
769   called = false;
770   sb1.consume(sb1.size());
771   boost::asio::async_read_until(s, sb1, match_char('Z'),
772       bindns::bind(async_read_handler, _1, &ec,
773         _2, &length, &called));
774   ios.reset();
775   ios.run();
776   BOOST_ASIO_CHECK(called);
777   BOOST_ASIO_CHECK(!ec);
778   BOOST_ASIO_CHECK(length == 26);
779 
780   s.reset(read_data, sizeof(read_data));
781   ec = boost::system::error_code();
782   length = 0;
783   called = false;
784   sb2.consume(sb2.size());
785   boost::asio::async_read_until(s, sb2, match_char('Z'),
786       bindns::bind(async_read_handler, _1, &ec,
787         _2, &length, &called));
788   ios.reset();
789   ios.run();
790   BOOST_ASIO_CHECK(called);
791   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
792   BOOST_ASIO_CHECK(length == 0);
793 
794   s.reset(read_data, sizeof(read_data));
795   s.next_read_length(1);
796   ec = boost::system::error_code();
797   length = 0;
798   called = false;
799   sb2.consume(sb2.size());
800   boost::asio::async_read_until(s, sb2, match_char('Z'),
801       bindns::bind(async_read_handler, _1, &ec,
802         _2, &length, &called));
803   ios.reset();
804   ios.run();
805   BOOST_ASIO_CHECK(called);
806   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
807   BOOST_ASIO_CHECK(length == 0);
808 
809   s.reset(read_data, sizeof(read_data));
810   s.next_read_length(10);
811   ec = boost::system::error_code();
812   length = 0;
813   called = false;
814   sb2.consume(sb2.size());
815   boost::asio::async_read_until(s, sb2, match_char('Z'),
816       bindns::bind(async_read_handler, _1, &ec,
817         _2, &length, &called));
818   ios.reset();
819   ios.run();
820   BOOST_ASIO_CHECK(called);
821   BOOST_ASIO_CHECK(ec == boost::asio::error::not_found);
822   BOOST_ASIO_CHECK(length == 0);
823 
824   s.reset(read_data, sizeof(read_data));
825   ec = boost::system::error_code();
826   length = 0;
827   called = false;
828   sb2.consume(sb2.size());
829   boost::asio::async_read_until(s, sb2, match_char('Y'),
830       bindns::bind(async_read_handler, _1, &ec,
831         _2, &length, &called));
832   ios.reset();
833   ios.run();
834   BOOST_ASIO_CHECK(called);
835   BOOST_ASIO_CHECK(!ec);
836   BOOST_ASIO_CHECK(length == 25);
837 
838   s.reset(read_data, sizeof(read_data));
839   s.next_read_length(1);
840   ec = boost::system::error_code();
841   length = 0;
842   called = false;
843   sb2.consume(sb2.size());
844   boost::asio::async_read_until(s, sb2, match_char('Y'),
845       bindns::bind(async_read_handler, _1, &ec,
846         _2, &length, &called));
847   ios.reset();
848   ios.run();
849   BOOST_ASIO_CHECK(called);
850   BOOST_ASIO_CHECK(!ec);
851   BOOST_ASIO_CHECK(length == 25);
852 
853   s.reset(read_data, sizeof(read_data));
854   s.next_read_length(10);
855   ec = boost::system::error_code();
856   length = 0;
857   called = false;
858   sb2.consume(sb2.size());
859   boost::asio::async_read_until(s, sb2, match_char('Y'),
860       bindns::bind(async_read_handler, _1, &ec,
861         _2, &length, &called));
862   ios.reset();
863   ios.run();
864   BOOST_ASIO_CHECK(called);
865   BOOST_ASIO_CHECK(!ec);
866   BOOST_ASIO_CHECK(length == 25);
867 
868   s.reset(read_data, sizeof(read_data));
869   sb2.consume(sb2.size());
870   int i = boost::asio::async_read_until(s, sb2, match_char('Y'),
871       archetypes::lazy_handler());
872   BOOST_ASIO_CHECK(i == 42);
873   ios.reset();
874   ios.run();
875 }
876 
877 BOOST_ASIO_TEST_SUITE
878 (
879   "read_until",
880   BOOST_ASIO_TEST_CASE(test_char_read_until)
881   BOOST_ASIO_TEST_CASE(test_string_read_until)
882   BOOST_ASIO_TEST_CASE(test_match_condition_read_until)
883   BOOST_ASIO_TEST_CASE(test_char_async_read_until)
884   BOOST_ASIO_TEST_CASE(test_string_async_read_until)
885   BOOST_ASIO_TEST_CASE(test_match_condition_async_read_until)
886 )
887