1 | // (C) Copyright Jorge Lodos 2008 |
2 | // (C) Copyright Jonathan Turkanis 2004 |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) |
5 | |
6 | // See http://www.boost.org/libs/iostreams for documentation. |
7 | |
8 | // This is the original (boost 1.34) boost::iostream test for the mapped files with the |
9 | // following modifications: |
10 | // 1. The namespace for the mapped file was changed to seglib::filemap. |
11 | // 2. Added test for privately mapped files. |
12 | // 3. The test test_writeable was added for mapped files. |
13 | // 4. The test test_resizeable was added for mapped files. |
14 | // |
15 | |
16 | #include <fstream> |
17 | #include <boost/config.hpp> |
18 | #include <boost/detail/workaround.hpp> |
19 | #include <boost/test/unit_test.hpp> |
20 | |
21 | #include <boost/iostreams/stream.hpp> |
22 | #include <boost/iostreams/device/mapped_file.hpp> |
23 | #include <boost/filesystem/path.hpp> |
24 | #include "detail/temp_file.hpp" |
25 | #include "detail/verification.hpp" |
26 | |
27 | // Code generation bugs cause tests to fail with global optimization. |
28 | #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
29 | # pragma optimize("g", off) |
30 | #endif |
31 | |
32 | namespace boost { namespace iostreams { namespace test { |
33 | |
34 | bool test_writeable(mapped_file& mf) |
35 | { |
36 | // Test writing |
37 | for (int i = 0; i < data_reps; ++i) { |
38 | memcpy(dest: mf.data(), src: narrow_data(), n: chunk_size); |
39 | char buf[chunk_size]; |
40 | memcpy(dest: buf, src: mf.const_data(), n: chunk_size); |
41 | if (strncmp(s1: buf, s2: narrow_data(), n: chunk_size) != 0) |
42 | return false; |
43 | memset(s: mf.data(), c: 0, n: chunk_size); |
44 | } |
45 | return true; |
46 | } |
47 | |
48 | bool test_resizeable(mapped_file& mf) |
49 | { |
50 | // Test resizing |
51 | mapped_file::size_type size = mf.size(); |
52 | if (size == 0) |
53 | return false; |
54 | mf.resize(new_size: size/2); |
55 | if (mf.size() != size/2) |
56 | return false; |
57 | mf.resize(new_size: size); |
58 | if (mf.size() != size) |
59 | return false; |
60 | return true; |
61 | } |
62 | |
63 | } } } // End namespaces test, iostreams, boost. |
64 | |
65 | void mapped_file_test() |
66 | { |
67 | using namespace boost::iostreams; |
68 | BOOST_TEST_MESSAGE("about to begin" ); |
69 | |
70 | //--------------Reading from a mapped_file_source-------------------------// |
71 | |
72 | { |
73 | // Note: the ifstream second is placed in a nested scope because |
74 | // closing and reopening a single ifstream failed for CW 9.4 on Windows. |
75 | |
76 | // Test reading from a stream based on a mapped_file_source, |
77 | // in chars. |
78 | boost::iostreams::test::test_file test1, test2; |
79 | boost::iostreams::stream<mapped_file_source> first(test1.name()); |
80 | { |
81 | std::ifstream second( test2.name().c_str(), |
82 | BOOST_IOS::in | BOOST_IOS::binary ); |
83 | BOOST_CHECK_MESSAGE( |
84 | boost::iostreams::test::compare_streams_in_chars(first, second), |
85 | "failed reading from stream<mapped_file_source> in chars" |
86 | ); |
87 | |
88 | BOOST_TEST_MESSAGE( |
89 | "done reading from stream<mapped_file_source> in chars" |
90 | ); |
91 | } |
92 | first.close(); |
93 | |
94 | // Test reading from a stream based on a mapped_file_source, |
95 | // in chunks. (Also tests reopening the stream.) |
96 | first.open(t: mapped_file_source(test1.name())); |
97 | { |
98 | std::ifstream second( test2.name().c_str(), |
99 | BOOST_IOS::in | BOOST_IOS::binary ); |
100 | BOOST_CHECK_MESSAGE( |
101 | boost::iostreams::test::compare_streams_in_chunks(first, second), |
102 | "failed reading from stream<mapped_file_source> in chunks" |
103 | ); |
104 | |
105 | BOOST_TEST_MESSAGE( |
106 | "done reading from stream<mapped_file_source> in chunks" |
107 | ); |
108 | } |
109 | } |
110 | |
111 | //--------------Writing to a mapped_file_sink-----------------------------// |
112 | |
113 | { |
114 | // Test writing to a stream based on a mapped_file_sink, in |
115 | // chars. |
116 | boost::iostreams::test::uppercase_file first, second; // Will overwrite these. |
117 | boost::iostreams::test::test_file test; |
118 | |
119 | boost::iostreams::stream<mapped_file_sink> out; |
120 | out.open(t: mapped_file_sink(first.name())); |
121 | boost::iostreams::test::write_data_in_chars(os&: out); |
122 | out.close(); |
123 | BOOST_CHECK_MESSAGE( |
124 | boost::iostreams::test::compare_files(first.name(), test.name()), |
125 | "failed writing to stream<mapped_file_sink> in chars" |
126 | ); |
127 | |
128 | BOOST_TEST_MESSAGE( |
129 | "done writing to stream<mapped_file_sink> in chars" |
130 | ); |
131 | |
132 | // Test writing to a stream based on a mapped_file_sink, in |
133 | // chunks. (Also tests reopening the stream.) |
134 | out.open(t: mapped_file_sink(second.name())); |
135 | boost::iostreams::test::write_data_in_chunks(os&: out); |
136 | out.close(); |
137 | BOOST_CHECK_MESSAGE( |
138 | boost::iostreams::test::compare_files(second.name(), test.name()), |
139 | "failed writing to stream<mapped_file_sink> in chunks" |
140 | ); |
141 | |
142 | BOOST_TEST_MESSAGE( |
143 | "done writing to stream<mapped_file_sink> in chunks" |
144 | ); |
145 | } |
146 | |
147 | //--------------Writing to a newly created file---------------------------// |
148 | |
149 | { |
150 | // Test writing to a newly created mapped file. |
151 | boost::iostreams::test::temp_file first, second; |
152 | boost::iostreams::test::test_file test; |
153 | |
154 | mapped_file_params p(first.name()); |
155 | p.new_file_size = boost::iostreams::test::data_reps * boost::iostreams::test::data_length(); |
156 | boost::iostreams::stream<mapped_file_sink> out; |
157 | out.open(t: mapped_file_sink(p)); |
158 | boost::iostreams::test::write_data_in_chars(os&: out); |
159 | out.close(); |
160 | BOOST_CHECK_MESSAGE( |
161 | boost::iostreams::test::compare_files(first.name(), test.name()), |
162 | "failed writing to newly created mapped file in chars" |
163 | ); |
164 | |
165 | |
166 | // Test writing to a newly created mapped file. |
167 | // (Also tests reopening the stream.) |
168 | p.path = second.name(); |
169 | out.open(t: mapped_file_sink(p)); |
170 | boost::iostreams::test::write_data_in_chunks(os&: out); |
171 | out.close(); |
172 | BOOST_CHECK_MESSAGE( |
173 | boost::iostreams::test::compare_files(second.name(), test.name()), |
174 | "failed writing to newly created mapped file in chunks" |
175 | ); |
176 | } |
177 | |
178 | //--------------Writing to a pre-existing file---------------------------// |
179 | { |
180 | // Test for Bug #3953 - writing to a pre-existing mapped file. |
181 | boost::iostreams::test::test_file first, test; |
182 | |
183 | mapped_file_params p(first.name()); |
184 | p.new_file_size = boost::iostreams::test::data_reps * boost::iostreams::test::data_length(); |
185 | boost::iostreams::stream<mapped_file_sink> out; |
186 | out.open(t: mapped_file_sink(p)); |
187 | boost::iostreams::test::write_data_in_chars(os&: out); |
188 | out.close(); |
189 | BOOST_CHECK_MESSAGE( |
190 | boost::iostreams::test::compare_files(first.name(), test.name()), |
191 | "failed writing to pre-existing mapped file in chars" |
192 | ); |
193 | } |
194 | |
195 | //--------------Random access with a mapped_file--------------------------// |
196 | |
197 | { |
198 | // Test reading, writing and seeking within a stream based on a |
199 | // mapped_file, in chars. |
200 | boost::iostreams::test::test_file test; |
201 | boost::iostreams::stream<mapped_file> io; |
202 | io.open(t: mapped_file(test.name())); |
203 | BOOST_CHECK_MESSAGE( |
204 | boost::iostreams::test::test_seekable_in_chars(io), |
205 | "failed seeking within stream<mapped_file> in chars" |
206 | ); |
207 | |
208 | BOOST_TEST_MESSAGE( |
209 | "done seeking within stream<mapped_file> in chars" |
210 | ); |
211 | |
212 | io.close(); |
213 | |
214 | // Test reading, writing and seeking within a stream based on a |
215 | // mapped_file, in chunks. (Also tests reopening the |
216 | // stream.) |
217 | io.open(t: mapped_file(test.name())); |
218 | BOOST_CHECK_MESSAGE( |
219 | boost::iostreams::test::test_seekable_in_chunks(io), |
220 | "failed seeking within stream<mapped_file> in chunks" |
221 | ); |
222 | |
223 | BOOST_TEST_MESSAGE( |
224 | "done seeking within stream<mapped_file> in chunks" |
225 | ); |
226 | } |
227 | |
228 | //--------------Resizing a mapped_file------------------------------------// |
229 | |
230 | { |
231 | // Test resizing a mapped_file. |
232 | boost::iostreams::test::test_file test; |
233 | mapped_file mf; |
234 | mf.open(path: test.name()); |
235 | BOOST_CHECK_MESSAGE( |
236 | boost::iostreams::test::test_resizeable(mf), |
237 | "failed resizing a mapped_file" |
238 | ); |
239 | |
240 | BOOST_TEST_MESSAGE( |
241 | "done resizing a mapped_file" |
242 | ); |
243 | } |
244 | |
245 | //--------------Random access with a private mapped_file------------------// |
246 | |
247 | { |
248 | // Use 2 copies of the file to compare later |
249 | boost::iostreams::test::test_file orig, copy; |
250 | |
251 | // Test reading and writing within a mapped_file. |
252 | // Since the file is privately mapped, it should remain |
253 | // unchanged after writing when opened in readonly mode. |
254 | mapped_file mf; |
255 | mf.open(path: orig.name(), flags: mapped_file::priv); |
256 | BOOST_CHECK_MESSAGE( |
257 | boost::iostreams::test::test_writeable(mf), |
258 | "failed seeking within private mapped_file" |
259 | ); |
260 | BOOST_CHECK_MESSAGE( |
261 | boost::iostreams::test::compare_files(orig.name(), copy.name()), |
262 | "failed writing to private mapped_file" |
263 | ); |
264 | |
265 | BOOST_TEST_MESSAGE( |
266 | "done seeking within private mapped_file" |
267 | ); |
268 | |
269 | mf.close(); |
270 | |
271 | // Test reopening the mapped file. |
272 | mf.open(path: orig.name(), flags: mapped_file::priv); |
273 | BOOST_CHECK_MESSAGE( |
274 | boost::iostreams::test::test_writeable(mf), |
275 | "failed reopening private mapped_file" |
276 | ); |
277 | BOOST_CHECK_MESSAGE( |
278 | boost::iostreams::test::compare_files(orig.name(), copy.name()), |
279 | "failed writing to reopened private mapped_file" |
280 | ); |
281 | |
282 | BOOST_TEST_MESSAGE( |
283 | "done reopening private mapped_file" |
284 | ); |
285 | } |
286 | |
287 | //-------------Check creating opening mapped_file with char*-------------// |
288 | |
289 | { |
290 | boost::iostreams::test::test_file orig; |
291 | char name[50]; |
292 | std::strncpy(dest: name, src: orig.name().c_str(), n: 50); |
293 | |
294 | mapped_file mf((char*) name); |
295 | |
296 | BOOST_CHECK_MESSAGE( |
297 | boost::iostreams::test::test_writeable(mf), |
298 | "failed seeking within private mapped_file" |
299 | ); |
300 | |
301 | mf.close(); |
302 | } |
303 | |
304 | // CYGWIN supports wide paths in boost::filesystem, but uses open() in the |
305 | // mapped file implementation and it is not configured to handle wide paths |
306 | // properly. See github issue https://github.com/boostorg/iostreams/issues/61 |
307 | #ifndef __CYGWIN__ |
308 | //---------Check creating opening mapped_file with filesystem3 path------// |
309 | { |
310 | boost::iostreams::test::test_file orig; |
311 | |
312 | mapped_file mf(boost::filesystem::path(orig.name())); |
313 | |
314 | BOOST_CHECK_MESSAGE( |
315 | boost::iostreams::test::test_writeable(mf), |
316 | "failed seeking within private mapped_file" |
317 | ); |
318 | |
319 | mf.close(); |
320 | } |
321 | #endif |
322 | } |
323 | |
324 | #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
325 | # pragma optimize("", on) |
326 | #endif |
327 | |
328 | boost::unit_test::test_suite* init_unit_test_suite(int, char* []) |
329 | { |
330 | boost::unit_test::test_suite* test = BOOST_TEST_SUITE("mapped_file test" ); |
331 | test->add(BOOST_TEST_CASE(&mapped_file_test)); |
332 | return test; |
333 | } |
334 | |