]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // |
92f5a8d4 | 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
b32b8144 FG |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
92f5a8d4 TL |
10 | #ifndef BOOST_BEAST_FILE_TEST_HPP |
11 | #define BOOST_BEAST_FILE_TEST_HPP | |
b32b8144 | 12 | |
92f5a8d4 TL |
13 | #include <boost/beast/_experimental/unit_test/suite.hpp> |
14 | #include <boost/beast/core/string.hpp> | |
15 | #include <boost/beast/core/file_base.hpp> | |
16 | #include <boost/filesystem/path.hpp> | |
17 | #include <boost/filesystem/operations.hpp> | |
f67539c2 | 18 | #include <boost/filesystem/fstream.hpp> |
92f5a8d4 | 19 | #include <cstdio> |
1e59de90 | 20 | #include <fstream> |
b32b8144 | 21 | #include <string> |
1e59de90 | 22 | #include <iterator> |
92f5a8d4 | 23 | #include <type_traits> |
b32b8144 FG |
24 | |
25 | namespace boost { | |
26 | namespace beast { | |
27 | ||
f67539c2 | 28 | template<class File, bool append_unicode_suffix = false> |
b32b8144 | 29 | void |
92f5a8d4 | 30 | test_file() |
b32b8144 | 31 | { |
92f5a8d4 TL |
32 | BOOST_STATIC_ASSERT( |
33 | is_file<File>::value); | |
34 | BOOST_STATIC_ASSERT( | |
35 | ! std::is_copy_constructible<File>::value); | |
36 | BOOST_STATIC_ASSERT( | |
37 | ! std::is_copy_assignable<File>::value); | |
b32b8144 | 38 | |
92f5a8d4 | 39 | namespace fs = boost::filesystem; |
b32b8144 | 40 | |
f67539c2 TL |
41 | static constexpr |
42 | #ifdef _WIN32 | |
43 | boost::winapi::WCHAR_ unicode_suffix[] = { 0xd83e, 0xdd84, 0x0000 }; // UTF-16-LE unicorn | |
44 | #else | |
45 | char unicode_suffix[] = { '\xf0', '\x9f', '\xa6', '\x84', '\x00' }; // UTF-8 unicorn | |
46 | #endif | |
47 | ||
92f5a8d4 TL |
48 | class temp_path |
49 | { | |
50 | fs::path path_; | |
f67539c2 | 51 | std::vector<char> utf8_str_; |
92f5a8d4 TL |
52 | |
53 | public: | |
54 | temp_path() | |
55 | : path_(fs::unique_path()) | |
92f5a8d4 | 56 | { |
f67539c2 TL |
57 | if (append_unicode_suffix) |
58 | path_ += unicode_suffix; | |
59 | #ifdef _WIN32 | |
60 | constexpr auto cp = boost::winapi::CP_UTF8_; | |
61 | constexpr auto flags = boost::winapi::WC_ERR_INVALID_CHARS_; | |
62 | auto sz = boost::winapi::WideCharToMultiByte( | |
63 | cp, flags, path_.c_str(), -1, nullptr, 0, | |
64 | nullptr, nullptr); | |
65 | BEAST_EXPECT(sz != 0); | |
66 | utf8_str_.resize(sz); | |
67 | auto ret = boost::winapi::WideCharToMultiByte( | |
68 | cp, flags, path_.c_str(), -1, | |
69 | utf8_str_.data(), sz, | |
70 | nullptr, nullptr); | |
71 | BEAST_EXPECT(ret == sz); | |
72 | #endif | |
92f5a8d4 TL |
73 | } |
74 | ||
75 | operator fs::path const&() | |
76 | { | |
77 | return path_; | |
78 | } | |
79 | ||
80 | operator char const*() | |
81 | { | |
f67539c2 TL |
82 | #ifdef _WIN32 |
83 | return utf8_str_.data(); | |
84 | #else | |
85 | return path_.c_str(); | |
86 | #endif | |
92f5a8d4 TL |
87 | } |
88 | }; | |
89 | ||
90 | auto const create = | |
1e59de90 | 91 | [](fs::path const& path, std::string const& data = "") |
92f5a8d4 | 92 | { |
92f5a8d4 | 93 | BEAST_EXPECT(! fs::exists(path)); |
f67539c2 TL |
94 | fs::ofstream out(path); |
95 | BEAST_EXPECT(out.is_open()); | |
1e59de90 TL |
96 | if (data.size()) |
97 | out.write(data.c_str(), data.size()); | |
92f5a8d4 TL |
98 | }; |
99 | ||
100 | auto const remove = | |
101 | [](fs::path const& path) | |
102 | { | |
103 | fs::remove(path); | |
f67539c2 | 104 | BEAST_EXPECT(! fs::exists(path)); |
92f5a8d4 TL |
105 | }; |
106 | ||
1e59de90 TL |
107 | auto const consume_file = |
108 | [](fs::path const& path) | |
109 | { | |
110 | // no exceptions - failure will result in an empty string | |
111 | std::ifstream in; | |
112 | in.open(path.native()); | |
113 | noskipws(in); | |
114 | auto s = std::string( | |
115 | std::istream_iterator<char>(in), | |
116 | std::istream_iterator<char>()); | |
117 | in.close(); | |
118 | return s; | |
119 | }; | |
120 | ||
92f5a8d4 TL |
121 | temp_path path; |
122 | ||
123 | // bad file descriptor | |
124 | { | |
125 | File f; | |
126 | char buf[1]; | |
127 | BEAST_EXPECT(! f.is_open()); | |
128 | BEAST_EXPECT(! fs::exists(path)); | |
129 | { | |
130 | error_code ec; | |
131 | f.size(ec); | |
132 | BEAST_EXPECT(ec == errc::bad_file_descriptor); | |
133 | } | |
134 | { | |
135 | error_code ec; | |
136 | f.pos(ec); | |
137 | BEAST_EXPECT(ec == errc::bad_file_descriptor); | |
138 | } | |
139 | { | |
140 | error_code ec; | |
141 | f.seek(0, ec); | |
142 | BEAST_EXPECT(ec == errc::bad_file_descriptor); | |
143 | } | |
144 | { | |
145 | error_code ec; | |
146 | f.read(buf, 0, ec); | |
147 | BEAST_EXPECT(ec == errc::bad_file_descriptor); | |
148 | } | |
149 | { | |
150 | error_code ec; | |
151 | f.write(buf, 0, ec); | |
152 | BEAST_EXPECT(ec == errc::bad_file_descriptor); | |
153 | } | |
154 | } | |
155 | ||
156 | // file_mode::read | |
157 | { | |
158 | { | |
159 | File f; | |
160 | error_code ec; | |
161 | create(path); | |
162 | f.open(path, file_mode::read, ec); | |
163 | BEAST_EXPECT(! ec); | |
164 | } | |
165 | remove(path); | |
166 | } | |
167 | ||
168 | // file_mode::scan | |
169 | { | |
170 | { | |
171 | File f; | |
172 | error_code ec; | |
173 | create(path); | |
174 | f.open(path, file_mode::scan, ec); | |
175 | BEAST_EXPECT(! ec); | |
176 | } | |
177 | remove(path); | |
178 | } | |
179 | ||
180 | // file_mode::write | |
181 | { | |
182 | { | |
183 | File f; | |
184 | error_code ec; | |
185 | BEAST_EXPECT(! fs::exists(path)); | |
186 | f.open(path, file_mode::write, ec); | |
187 | BEAST_EXPECT(! ec); | |
188 | BEAST_EXPECT(fs::exists(path)); | |
189 | } | |
190 | { | |
191 | File f; | |
192 | error_code ec; | |
193 | BEAST_EXPECT(fs::exists(path)); | |
194 | f.open(path, file_mode::write, ec); | |
195 | BEAST_EXPECT(! ec); | |
196 | BEAST_EXPECT(fs::exists(path)); | |
197 | } | |
198 | remove(path); | |
199 | } | |
200 | ||
201 | // file_mode::write_new | |
202 | { | |
203 | { | |
204 | File f; | |
205 | error_code ec; | |
206 | BEAST_EXPECT(! fs::exists(path)); | |
207 | f.open(path, file_mode::write_new, ec); | |
208 | BEAST_EXPECTS(! ec, ec.message()); | |
209 | BEAST_EXPECT(fs::exists(path)); | |
210 | } | |
211 | { | |
212 | File f; | |
213 | error_code ec; | |
214 | BEAST_EXPECT(fs::exists(path)); | |
215 | f.open(path, file_mode::write_new, ec); | |
216 | BEAST_EXPECT(ec); | |
217 | } | |
218 | remove(path); | |
219 | } | |
220 | ||
221 | // file_mode::write_existing | |
222 | { | |
223 | { | |
224 | File f; | |
225 | error_code ec; | |
226 | BEAST_EXPECT(! fs::exists(path)); | |
227 | f.open(path, file_mode::write_existing, ec); | |
228 | BEAST_EXPECT(ec); | |
229 | BEAST_EXPECT(! fs::exists(path)); | |
230 | } | |
231 | { | |
232 | File f; | |
233 | error_code ec; | |
234 | create(path); | |
235 | BEAST_EXPECT(fs::exists(path)); | |
236 | f.open(path, file_mode::write_existing, ec); | |
237 | BEAST_EXPECT(! ec); | |
238 | } | |
239 | remove(path); | |
240 | } | |
241 | ||
242 | // file_mode::append | |
243 | { | |
244 | { | |
245 | File f; | |
246 | error_code ec; | |
247 | BEAST_EXPECT(! fs::exists(path)); | |
248 | f.open(path, file_mode::append, ec); | |
249 | BEAST_EXPECT(! ec); | |
250 | BEAST_EXPECT(fs::exists(path)); | |
1e59de90 TL |
251 | static const std::string extra = "the"; |
252 | f.write(extra.c_str(), extra.size(), ec); | |
253 | BEAST_EXPECT(!ec); | |
254 | f.close(ec); | |
255 | auto s = consume_file(path); | |
256 | BEAST_EXPECT(s == "the"); | |
92f5a8d4 | 257 | } |
1e59de90 | 258 | |
92f5a8d4 TL |
259 | { |
260 | File f; | |
261 | error_code ec; | |
262 | BEAST_EXPECT(fs::exists(path)); | |
263 | f.open(path, file_mode::append, ec); | |
264 | BEAST_EXPECT(! ec); | |
265 | BEAST_EXPECT(fs::exists(path)); | |
1e59de90 TL |
266 | static const std::string extra = " cat"; |
267 | f.write(extra.c_str(), extra.size(), ec); | |
268 | BEAST_EXPECT(!ec); | |
269 | f.close(ec); | |
270 | auto s = consume_file(path); | |
271 | BEAST_EXPECTS(s == "the cat", s); | |
92f5a8d4 TL |
272 | } |
273 | remove(path); | |
274 | } | |
275 | ||
276 | // file_mode::append_existing | |
277 | { | |
278 | { | |
279 | File f; | |
280 | error_code ec; | |
281 | BEAST_EXPECT(! fs::exists(path)); | |
282 | f.open(path, file_mode::append_existing, ec); | |
283 | BEAST_EXPECT(ec); | |
284 | BEAST_EXPECT(! fs::exists(path)); | |
285 | } | |
286 | remove(path); | |
287 | { | |
288 | File f; | |
289 | error_code ec; | |
1e59de90 | 290 | create(path, "the cat"); |
92f5a8d4 TL |
291 | f.open(path, file_mode::append_existing, ec); |
292 | BEAST_EXPECT(! ec); | |
1e59de90 TL |
293 | static std::string const extra = " sat"; |
294 | f.write(extra.c_str(), extra.size(), ec); | |
295 | BEAST_EXPECT(!ec); | |
296 | f.close(ec); | |
297 | BEAST_EXPECT(!ec); | |
298 | auto s = consume_file(path); | |
299 | BEAST_EXPECTS(s == "the cat sat", s); | |
92f5a8d4 TL |
300 | } |
301 | remove(path); | |
302 | } | |
303 | ||
304 | // special members | |
b32b8144 FG |
305 | { |
306 | { | |
307 | File f1; | |
92f5a8d4 TL |
308 | error_code ec; |
309 | f1.open(path, file_mode::write, ec); | |
310 | BEAST_EXPECT(! ec); | |
311 | BEAST_EXPECT(f1.is_open()); | |
312 | ||
313 | // move constructor | |
314 | File f2(std::move(f1)); | |
315 | BEAST_EXPECT(! f1.is_open()); | |
316 | BEAST_EXPECT(f2.is_open()); | |
317 | ||
318 | // move assignment | |
b32b8144 FG |
319 | File f3; |
320 | f3 = std::move(f2); | |
92f5a8d4 TL |
321 | BEAST_EXPECT(! f2.is_open()); |
322 | BEAST_EXPECT(f3.is_open()); | |
323 | } | |
324 | remove(path); | |
b32b8144 FG |
325 | } |
326 | ||
92f5a8d4 TL |
327 | // re-open |
328 | { | |
329 | { | |
330 | File f; | |
331 | error_code ec; | |
332 | f.open(path, file_mode::write, ec); | |
333 | BEAST_EXPECT(! ec); | |
334 | f.open(path, file_mode::write, ec); | |
335 | BEAST_EXPECT(! ec); | |
336 | } | |
337 | remove(path); | |
338 | } | |
b32b8144 | 339 | |
92f5a8d4 TL |
340 | // re-assign |
341 | { | |
342 | temp_path path2; | |
343 | { | |
344 | error_code ec; | |
b32b8144 | 345 | |
92f5a8d4 TL |
346 | File f1; |
347 | f1.open(path, file_mode::write, ec); | |
348 | BEAST_EXPECT(! ec); | |
b32b8144 | 349 | |
92f5a8d4 TL |
350 | File f2; |
351 | f2.open(path2, file_mode::write, ec); | |
352 | BEAST_EXPECT(! ec); | |
b32b8144 | 353 | |
92f5a8d4 TL |
354 | f2 = std::move(f1); |
355 | BEAST_EXPECT(! f1.is_open()); | |
356 | BEAST_EXPECT(f2.is_open()); | |
357 | } | |
358 | remove(path); | |
359 | remove(path2); | |
360 | } | |
b32b8144 | 361 | |
92f5a8d4 TL |
362 | // self-move |
363 | { | |
364 | { | |
365 | File f; | |
366 | error_code ec; | |
367 | f.open(path, file_mode::write, ec); | |
368 | BEAST_EXPECT(! ec); | |
369 | f = std::move(f); | |
370 | BEAST_EXPECT(f.is_open()); | |
371 | } | |
372 | remove(path); | |
373 | } | |
b32b8144 | 374 | |
92f5a8d4 TL |
375 | // native_handle |
376 | { | |
377 | { | |
378 | File f; | |
379 | auto none = f.native_handle(); | |
380 | error_code ec; | |
381 | f.open(path, file_mode::write, ec); | |
382 | BEAST_EXPECT(! ec); | |
383 | auto fd = f.native_handle(); | |
384 | BEAST_EXPECT(fd != none); | |
385 | f.native_handle(none); | |
386 | BEAST_EXPECT(! f.is_open()); | |
387 | } | |
388 | remove(path); | |
389 | } | |
b32b8144 | 390 | |
92f5a8d4 TL |
391 | // read and write |
392 | { | |
393 | string_view const s = "Hello, world!"; | |
b32b8144 | 394 | |
92f5a8d4 TL |
395 | // write |
396 | { | |
397 | File f; | |
398 | error_code ec; | |
399 | f.open(path, file_mode::write, ec); | |
400 | BEAST_EXPECT(! ec); | |
b32b8144 | 401 | |
92f5a8d4 TL |
402 | f.write(s.data(), s.size(), ec); |
403 | BEAST_EXPECT(! ec); | |
b32b8144 | 404 | |
92f5a8d4 TL |
405 | auto size = f.size(ec); |
406 | BEAST_EXPECT(! ec); | |
407 | BEAST_EXPECT(size == s.size()); | |
b32b8144 | 408 | |
92f5a8d4 TL |
409 | auto pos = f.pos(ec); |
410 | BEAST_EXPECT(! ec); | |
411 | BEAST_EXPECT(pos == size); | |
b32b8144 | 412 | |
92f5a8d4 TL |
413 | f.close(ec); |
414 | BEAST_EXPECT(! ec); | |
415 | } | |
416 | ||
417 | // read | |
418 | { | |
419 | File f; | |
420 | error_code ec; | |
421 | f.open(path, file_mode::read, ec); | |
422 | BEAST_EXPECT(! ec); | |
b32b8144 | 423 | |
92f5a8d4 TL |
424 | std::string buf; |
425 | buf.resize(s.size()); | |
426 | f.read(&buf[0], buf.size(), ec); | |
427 | BEAST_EXPECT(! ec); | |
428 | BEAST_EXPECT(buf == s); | |
b32b8144 | 429 | |
92f5a8d4 TL |
430 | f.seek(1, ec); |
431 | BEAST_EXPECT(! ec); | |
432 | buf.resize(3); | |
433 | f.read(&buf[0], buf.size(), ec); | |
434 | BEAST_EXPECT(! ec); | |
435 | BEAST_EXPECT(buf == "ell"); | |
b32b8144 | 436 | |
92f5a8d4 TL |
437 | auto pos = f.pos(ec); |
438 | BEAST_EXPECT(! ec); | |
439 | BEAST_EXPECT(pos == 4); | |
440 | } | |
441 | remove(path); | |
442 | } | |
b32b8144 | 443 | |
92f5a8d4 | 444 | BEAST_EXPECT(! fs::exists(path)); |
b32b8144 FG |
445 | } |
446 | ||
447 | } // beast | |
448 | } // boost | |
449 | ||
450 | #endif |