1 /*
2  * Distributed under the Boost Software License, Version 1.0.(See accompanying
3  * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
4  *
5  * See http://www.boost.org/libs/iostreams for documentation.
6  *
7  * Tests the facilities defined in the header
8  * libs/iostreams/test/detail/operation_sequence.hpp
9  *
10  * File:        libs/iostreams/test/operation_sequence_test.cpp
11  * Date:        Mon Dec 10 18:58:19 MST 2007
12  * Copyright:   2007-2008 CodeRage, LLC
13  * Author:      Jonathan Turkanis
14  * Contact:     turkanis at coderage dot com
15  */
16 
17 #include <stdexcept>
18 #include <boost/test/test_tools.hpp>
19 #include <boost/test/unit_test.hpp>
20 #include "detail/operation_sequence.hpp"
21 
22 using namespace std;
23 using namespace boost;
24 using namespace boost::iostreams::test;
25 using boost::unit_test::test_suite;
26 
27         // Infrastructure for checking that operations are
28         // executed in the correct order
29 
operation_sequence_test()30 void operation_sequence_test()
31 {
32     // Test creating a duplicate operation
33     {
34         operation_sequence seq;
35         operation op = seq.new_operation(1);
36         BOOST_CHECK_THROW(seq.new_operation(1), runtime_error);
37     }
38 
39     // Test reusing an operation id after first operation is destroyed
40     {
41         operation_sequence seq;
42         seq.new_operation(1);
43         BOOST_CHECK_NO_THROW(seq.new_operation(1));
44     }
45 
46     // Test creating operations with illegal error codes
47     {
48         operation_sequence seq;
49         BOOST_CHECK_THROW(seq.new_operation(1, -100), runtime_error);
50         BOOST_CHECK_THROW(
51             seq.new_operation(1, BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR + 1),
52             runtime_error
53         );
54     }
55 
56     // Test two successful operations executed out of order
57     {
58         operation_sequence  seq;
59         operation           op1 = seq.new_operation(1);
60         operation           op2 = seq.new_operation(2);
61         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
62         BOOST_CHECK_NO_THROW(op2.execute());
63         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
64         BOOST_CHECK_NO_THROW(op1.execute());
65         BOOST_CHECK(seq.is_failure());
66     }
67 
68     // Test executing an operation twice without resetting the sequence
69     {
70         operation_sequence  seq;
71         operation           op = seq.new_operation(1);
72         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
73         BOOST_CHECK_NO_THROW(op.execute());
74         BOOST_CHECK(seq.is_success());
75         BOOST_CHECK_NO_THROW(op.execute());
76         BOOST_CHECK(seq.is_failure());
77     }
78 
79     // Test creating an operation after operation execution has commenced
80     {
81         operation_sequence  seq;
82         operation           op1 = seq.new_operation(1);
83         operation           op2 = seq.new_operation(2);
84         operation           op3;
85         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
86         BOOST_CHECK_NO_THROW(op1.execute());
87         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
88         BOOST_CHECK_THROW(op3 = seq.new_operation(3), runtime_error);
89         BOOST_CHECK_NO_THROW(op2.execute());
90         BOOST_CHECK(seq.is_success());
91     }
92 
93     // Test three successful operations with consecutive ids, executed in order
94     {
95         operation_sequence  seq;
96         operation           op1 = seq.new_operation(1);
97         operation           op2 = seq.new_operation(2);
98         operation           op3 = seq.new_operation(3);
99 
100         // First pass
101         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
102         op1.execute();
103         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
104         op2.execute();
105         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
106         op3.execute();
107         BOOST_CHECK(seq.is_success());
108 
109         // Second pass
110         seq.reset();
111         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
112         op1.execute();
113         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
114         op2.execute();
115         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
116         op3.execute();
117         BOOST_CHECK(seq.is_success());
118     }
119 
120     // Test three successful operations with non-consecutive ids,
121     // executed in order
122     {
123         operation_sequence  seq;
124         operation           op2 = seq.new_operation(2);
125         operation           op3 = seq.new_operation(101);
126         operation           op1 = seq.new_operation(-43);
127 
128         // First pass
129         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
130         op1.execute();
131         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
132         op2.execute();
133         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
134         op3.execute();
135         BOOST_CHECK(seq.is_success());
136 
137         // Second pass
138         seq.reset();
139         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
140         op1.execute();
141         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
142         op2.execute();
143         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
144         op3.execute();
145         BOOST_CHECK(seq.is_success());
146     }
147 
148     // Test checking for success after one of three operations
149     // has been destroyed
150     {
151         operation_sequence  seq;
152         operation           op1 = seq.new_operation(1);
153         operation           op3 = seq.new_operation(3);
154 
155         {
156             operation       op2 = seq.new_operation(2);
157             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
158             op1.execute();
159             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
160             op2.execute();
161             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
162             op3.execute();
163         }
164         BOOST_CHECK(seq.is_success());
165     }
166 
167     // Test executing an operation sequence twice, with one of the
168     // operations replaced with a new operation with the same id
169     // in the second pass
170     {
171         operation_sequence  seq;
172         operation           op1 = seq.new_operation(1);
173         operation           op3 = seq.new_operation(3);
174 
175         // First pass
176         {
177             operation       op2 = seq.new_operation(2);
178             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
179             op1.execute();
180             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
181             op2.execute();
182             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
183             op3.execute();
184             BOOST_CHECK(seq.is_success());
185         }
186 
187         // Second pass
188         seq.reset();
189         {
190             operation       op2 = seq.new_operation(2);
191             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
192             op1.execute();
193             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
194             op2.execute();
195             BOOST_CHECK(!seq.is_failure() && !seq.is_success());
196             op3.execute();
197             BOOST_CHECK(seq.is_success());
198         }
199     }
200 
201     // Test three operations executed in order, the first of which throws
202     {
203         operation_sequence  seq;
204         operation           op1 = seq.new_operation(1, 1);
205         operation           op2 = seq.new_operation(2);
206         operation           op3 = seq.new_operation(3);
207         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
208         BOOST_CHECK_THROW(op1.execute(), operation_error<1>);
209         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
210         BOOST_CHECK_NO_THROW(op2.execute());
211         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
212         BOOST_CHECK_NO_THROW(op3.execute());
213         BOOST_CHECK(seq.is_success());
214     }
215 
216     // Test three operations executed in order, the second of which throws
217     {
218         operation_sequence  seq;
219         operation           op1 = seq.new_operation(1);
220         operation           op2 = seq.new_operation(2, 2);
221         operation           op3 = seq.new_operation(3);
222         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
223         BOOST_CHECK_NO_THROW(op1.execute());
224         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
225         BOOST_CHECK_THROW(op2.execute(), operation_error<2>);
226         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
227         BOOST_CHECK_NO_THROW(op3.execute());
228         BOOST_CHECK(seq.is_success());
229     }
230 
231     // Test three operations executed in order, the third of which throws
232     {
233         operation_sequence  seq;
234         operation           op1 = seq.new_operation(1);
235         operation           op2 = seq.new_operation(2);
236         operation           op3 = seq.new_operation(3, 3);
237         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
238         BOOST_CHECK_NO_THROW(op1.execute());
239         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
240         BOOST_CHECK_NO_THROW(op2.execute());
241         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
242         BOOST_CHECK_THROW(op3.execute(), operation_error<3>);
243         BOOST_CHECK(seq.is_success());
244     }
245 
246     // Test three operations executed in order, the first and
247     // third of which throw
248     {
249         operation_sequence  seq;
250         operation           op1 = seq.new_operation(1, 1);
251         operation           op2 = seq.new_operation(2);
252         operation           op3 = seq.new_operation(3, 3);
253         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
254         BOOST_CHECK_THROW(op1.execute(), operation_error<1>);
255         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
256         BOOST_CHECK_NO_THROW(op2.execute());
257         BOOST_CHECK(!seq.is_failure() && !seq.is_success());
258         BOOST_CHECK_THROW(op3.execute(), operation_error<3>);
259         BOOST_CHECK(seq.is_success());
260     }
261 }
262 
init_unit_test_suite(int,char * [])263 test_suite* init_unit_test_suite(int, char* [])
264 {
265     test_suite* test = BOOST_TEST_SUITE("execute test");
266     test->add(BOOST_TEST_CASE(&operation_sequence_test));
267     return test;
268 }
269