path_unit_test.cpp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  1. // filesystem path_unit_test.cpp --------------------------------------------------- //
  2. // Copyright Beman Dawes 2008, 2009
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // See http://www.boost.org/LICENSE_1_0.txt
  5. // Library home page: http://www.boost.org/libs/filesystem
  6. // ---------------------------------------------------------------------------------- //
  7. //
  8. // The purpose of this test is to ensure that each function in the public
  9. // interface can be called with arguments of the appropriate types. It does
  10. // not attempt to verify that the full range of values for each argument
  11. // are processed correctly.
  12. //
  13. // For full functionality tests, including probes with many different argument
  14. // values, see path_test.cpp and other test programs.
  15. //
  16. // ---------------------------------------------------------------------------------- //
  17. #include <boost/config/warning_disable.hpp>
  18. // See deprecated_test for tests of deprecated features
  19. #ifndef BOOST_FILESYSTEM_NO_DEPRECATED
  20. # define BOOST_FILESYSTEM_NO_DEPRECATED
  21. #endif
  22. #ifndef BOOST_SYSTEM_NO_DEPRECATED
  23. # define BOOST_SYSTEM_NO_DEPRECATED
  24. #endif
  25. #include <boost/filesystem/path.hpp>
  26. #include <boost/filesystem/detail/utf8_codecvt_facet.hpp> // for imbue tests
  27. #include "test_codecvt.hpp" // for codecvt arg tests
  28. #include <boost/detail/lightweight_test_report.hpp>
  29. #include <boost/smart_ptr.hpp> // used constructor tests
  30. #include <boost/functional/hash.hpp>
  31. #include <iostream>
  32. #include <iomanip>
  33. #include <sstream>
  34. #include <string>
  35. #include <cstring>
  36. #include <cwchar>
  37. #include <locale>
  38. #include <list>
  39. namespace fs = boost::filesystem;
  40. namespace bs = boost::system;
  41. using boost::filesystem::path;
  42. using std::cout;
  43. using std::endl;
  44. using std::string;
  45. using std::wstring;
  46. #define CHECK(x) check(x, __FILE__, __LINE__)
  47. #define PATH_IS(a, b) check_path(a, b, __FILE__, __LINE__)
  48. #define NATIVE_IS(p, s, ws) check_native(p, s, ws, __FILE__, __LINE__)
  49. #define IS(a,b) check_equal(a, b, __FILE__, __LINE__)
  50. #if defined(_MSC_VER)
  51. # pragma warning(push) // Save warning settings.
  52. # pragma warning(disable : 4428) // Disable universal-character-name encountered in source warning.
  53. #endif
  54. namespace
  55. {
  56. boost::system::error_code ec;
  57. const boost::system::error_code ok;
  58. const boost::system::error_code ng(-1, boost::system::system_category());
  59. std::string platform(BOOST_PLATFORM);
  60. void check_path(const path& source,
  61. const wstring& expected, const char* file, int line)
  62. {
  63. if (source == expected) return;
  64. ++::boost::detail::test_errors();
  65. std::cout << file;
  66. std::wcout << L'(' << line << L"): source.wstring(): \""
  67. << source.wstring()
  68. << L"\" != expected: \"" << expected
  69. << L"\"\n" ;
  70. }
  71. # ifdef BOOST_WINDOWS_API
  72. void check_native(const path& p,
  73. const string&, const wstring& expected, const char* file, int line)
  74. # else
  75. void check_native(const path& p,
  76. const string& expected, const wstring&, const char* file, int line)
  77. # endif
  78. {
  79. if (p.native() == expected) return;
  80. ++::boost::detail::test_errors();
  81. std::cout << file << '(' << line << "): native() is not equal expected\n"
  82. " native---: " << std::hex;
  83. path::string_type nat(p.native());
  84. for (path::string_type::const_iterator it = nat.begin(); it != nat.end(); ++it)
  85. std::cout << long(*it) << ' ';
  86. std::cout << "\n expected-: ";
  87. for (path::string_type::const_iterator it = expected.begin(); it != expected.end(); ++it)
  88. std::cout << long(*it) << ' ';
  89. std::cout << std::dec << std::endl;
  90. }
  91. template< class T1, class T2 >
  92. void check_equal(const T1& value,
  93. const T2& expected, const char* file, int line)
  94. {
  95. if (value == expected) return;
  96. ++::boost::detail::test_errors();
  97. std::cout << file;
  98. std::wcout << L'(' << line << L"): value: \"" << value
  99. << L"\" != expected: \"" << expected
  100. << L"\"\n" ;
  101. }
  102. void check(bool ok_, const char* file, int line)
  103. {
  104. if (ok_) return;
  105. ++::boost::detail::test_errors();
  106. std::cout << file << '(' << line << "): test failed\n";
  107. }
  108. string s("string");
  109. wstring ws(L"wstring");
  110. std::list<char> l; // see main() for initialization to s, t, r, i, n, g
  111. std::list<wchar_t> wl; // see main() for initialization to w, s, t, r, i, n, g
  112. std::vector<char> v; // see main() for initialization to f, u, z
  113. std::vector<wchar_t> wv; // see main() for initialization to w, f, u, z
  114. class Base {};
  115. class Derived : public Base {};
  116. void fun(const boost::shared_ptr< Base >&) {}
  117. // test_constructors ---------------------------------------------------------------//
  118. void test_constructors()
  119. {
  120. std::cout << "testing constructors..." << std::endl;
  121. path x0; // default constructor
  122. PATH_IS(x0, L"");
  123. BOOST_TEST_EQ(x0.native().size(), 0U);
  124. path x1(l.begin(), l.end()); // iterator range char
  125. PATH_IS(x1, L"string");
  126. BOOST_TEST_EQ(x1.native().size(), 6U);
  127. path x2(x1); // copy constructor
  128. PATH_IS(x2, L"string");
  129. BOOST_TEST_EQ(x2.native().size(), 6U);
  130. path x3(wl.begin(), wl.end()); // iterator range wchar_t
  131. PATH_IS(x3, L"wstring");
  132. BOOST_TEST_EQ(x3.native().size(), 7U);
  133. // contiguous containers
  134. path x4(string("std::string")); // std::string
  135. PATH_IS(x4, L"std::string");
  136. BOOST_TEST_EQ(x4.native().size(), 11U);
  137. path x5(wstring(L"std::wstring")); // std::wstring
  138. PATH_IS(x5, L"std::wstring");
  139. BOOST_TEST_EQ(x5.native().size(), 12U);
  140. path x4v(v); // std::vector<char>
  141. PATH_IS(x4v, L"fuz");
  142. BOOST_TEST_EQ(x4v.native().size(), 3U);
  143. path x5v(wv); // std::vector<wchar_t>
  144. PATH_IS(x5v, L"wfuz");
  145. BOOST_TEST_EQ(x5v.native().size(), 4U);
  146. path x6("array char"); // array char
  147. PATH_IS(x6, L"array char");
  148. BOOST_TEST_EQ(x6.native().size(), 10U);
  149. path x7(L"array wchar_t"); // array wchar_t
  150. PATH_IS(x7, L"array wchar_t");
  151. BOOST_TEST_EQ(x7.native().size(), 13U);
  152. char char_array[100];
  153. std::strcpy(char_array, "big array char");
  154. path x6o(char_array); // array char, only partially full
  155. PATH_IS(x6o, L"big array char");
  156. BOOST_TEST_EQ(x6o.native().size(), 14U);
  157. wchar_t wchar_array[100];
  158. std::wcscpy(wchar_array, L"big array wchar_t");
  159. path x7o(wchar_array); // array char, only partially full
  160. PATH_IS(x7o, L"big array wchar_t");
  161. BOOST_TEST_EQ(x7o.native().size(), 17U);
  162. path x8(s.c_str()); // const char* null terminated
  163. PATH_IS(x8, L"string");
  164. BOOST_TEST_EQ(x8.native().size(), 6U);
  165. path x9(ws.c_str()); // const wchar_t* null terminated
  166. PATH_IS(x9, L"wstring");
  167. BOOST_TEST_EQ(x9.native().size(), 7U);
  168. path x8nc(const_cast<char*>(s.c_str())); // char* null terminated
  169. PATH_IS(x8nc, L"string");
  170. BOOST_TEST_EQ(x8nc.native().size(), 6U);
  171. path x9nc(const_cast<wchar_t*>(ws.c_str())); // wchar_t* null terminated
  172. PATH_IS(x9nc, L"wstring");
  173. BOOST_TEST_EQ(x9nc.native().size(), 7U);
  174. // non-contiguous containers
  175. path x10(l); // std::list<char>
  176. PATH_IS(x10, L"string");
  177. BOOST_TEST_EQ(x10.native().size(), 6U);
  178. path xll(wl); // std::list<wchar_t>
  179. PATH_IS(xll, L"wstring");
  180. BOOST_TEST_EQ(xll.native().size(), 7U);
  181. // easy-to-make coding errors
  182. // path e1(x0, path::codecvt()); // fails to compile, and that is OK
  183. boost::shared_ptr< Derived > pDerived( new Derived() );
  184. fun( pDerived ); // tests constructor member template enable_if working correctly;
  185. // will fail to compile if enable_if not taking path off the table
  186. }
  187. path x;
  188. path y;
  189. // test_assignments ----------------------------------------------------------------//
  190. void test_assignments()
  191. {
  192. std::cout << "testing assignments..." << std::endl;
  193. x = path("yet another path"); // another path
  194. PATH_IS(x, L"yet another path");
  195. BOOST_TEST_EQ(x.native().size(), 16U);
  196. x = x; // self-assignment
  197. PATH_IS(x, L"yet another path");
  198. BOOST_TEST_EQ(x.native().size(), 16U);
  199. x.assign(l.begin(), l.end()); // iterator range char
  200. PATH_IS(x, L"string");
  201. x.assign(wl.begin(), wl.end()); // iterator range wchar_t
  202. PATH_IS(x, L"wstring");
  203. x = string("std::string"); // container char
  204. PATH_IS(x, L"std::string");
  205. x = wstring(L"std::wstring"); // container wchar_t
  206. PATH_IS(x, L"std::wstring");
  207. x = "array char"; // array char
  208. PATH_IS(x, L"array char");
  209. x = L"array wchar"; // array wchar_t
  210. PATH_IS(x, L"array wchar");
  211. x = s.c_str(); // const char* null terminated
  212. PATH_IS(x, L"string");
  213. x = ws.c_str(); // const wchar_t* null terminated
  214. PATH_IS(x, L"wstring");
  215. }
  216. // test_move_construction_and_assignment -------------------------------------------//
  217. void test_move_construction_and_assignment()
  218. {
  219. std::cout << "testing move_construction_and_assignment..." << std::endl;
  220. # if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  221. path from("long enough to avoid small object optimization");
  222. path to(std::move(from));
  223. BOOST_TEST(to == "long enough to avoid small object optimization");
  224. if (!from.empty())
  225. cout << "Note: move construction did not result in empty source path" << endl;
  226. path from2("long enough to avoid small object optimization");
  227. path to2;
  228. to2 = std::move(from2);
  229. BOOST_TEST(to2 == "long enough to avoid small object optimization");
  230. if (!from2.empty())
  231. cout << "Note: move assignment did not result in empty rhs path" << endl;
  232. # else
  233. std::cout <<
  234. "Test skipped because compiler does not support move semantics" << std::endl;
  235. # endif
  236. }
  237. // test_appends --------------------------------------------------------------------//
  238. void test_appends()
  239. {
  240. std::cout << "testing appends..." << std::endl;
  241. # ifdef BOOST_WINDOWS_API
  242. # define BOOST_FS_FOO L"/foo\\"
  243. # else // POSIX paths
  244. # define BOOST_FS_FOO L"/foo/"
  245. # endif
  246. x = "/foo";
  247. x /= path(""); // empty path
  248. PATH_IS(x, L"/foo");
  249. x = "/foo";
  250. x /= path("/"); // slash path
  251. PATH_IS(x, L"/foo/");
  252. x = "/foo";
  253. x /= path("/boo"); // slash path
  254. PATH_IS(x, L"/foo/boo");
  255. x = "/foo";
  256. x /= x; // self-append
  257. PATH_IS(x, L"/foo/foo");
  258. x = "/foo";
  259. x /= path("yet another path"); // another path
  260. PATH_IS(x, BOOST_FS_FOO L"yet another path");
  261. x = "/foo";
  262. x.append(l.begin(), l.end()); // iterator range char
  263. PATH_IS(x, BOOST_FS_FOO L"string");
  264. x = "/foo";
  265. x.append(wl.begin(), wl.end()); // iterator range wchar_t
  266. PATH_IS(x, BOOST_FS_FOO L"wstring");
  267. x = "/foo";
  268. x /= string("std::string"); // container char
  269. PATH_IS(x, BOOST_FS_FOO L"std::string");
  270. x = "/foo";
  271. x /= wstring(L"std::wstring"); // container wchar_t
  272. PATH_IS(x, BOOST_FS_FOO L"std::wstring");
  273. x = "/foo";
  274. x /= "array char"; // array char
  275. PATH_IS(x, BOOST_FS_FOO L"array char");
  276. x = "/foo";
  277. x /= L"array wchar"; // array wchar_t
  278. PATH_IS(x, BOOST_FS_FOO L"array wchar");
  279. x = "/foo";
  280. x /= s.c_str(); // const char* null terminated
  281. PATH_IS(x, BOOST_FS_FOO L"string");
  282. x = "/foo";
  283. x /= ws.c_str(); // const wchar_t* null terminated
  284. PATH_IS(x, BOOST_FS_FOO L"wstring");
  285. }
  286. // test_concats --------------------------------------------------------------------//
  287. void test_concats()
  288. {
  289. std::cout << "testing concats..." << std::endl;
  290. x = "/foo";
  291. x += path(""); // empty path
  292. PATH_IS(x, L"/foo");
  293. x = "/foo";
  294. x += path("/"); // slash path
  295. PATH_IS(x, L"/foo/");
  296. x = "/foo";
  297. x += path("boo"); // slash path
  298. PATH_IS(x, L"/fooboo");
  299. x = "foo";
  300. x += x; // self-append
  301. PATH_IS(x, L"foofoo");
  302. x = "foo-";
  303. x += path("yet another path"); // another path
  304. PATH_IS(x, L"foo-yet another path");
  305. x = "foo-";
  306. x.concat(l.begin(), l.end()); // iterator range char
  307. PATH_IS(x, L"foo-string");
  308. x = "foo-";
  309. x.concat(wl.begin(), wl.end()); // iterator range wchar_t
  310. PATH_IS(x, L"foo-wstring");
  311. x = "foo-";
  312. x += string("std::string"); // container char
  313. PATH_IS(x, L"foo-std::string");
  314. x = "foo-";
  315. x += wstring(L"std::wstring"); // container wchar_t
  316. PATH_IS(x, L"foo-std::wstring");
  317. x = "foo-";
  318. x += "array char"; // array char
  319. PATH_IS(x, L"foo-array char");
  320. x = "foo-";
  321. x += L"array wchar"; // array wchar_t
  322. PATH_IS(x, L"foo-array wchar");
  323. x = "foo-";
  324. x += s.c_str(); // const char* null terminated
  325. PATH_IS(x, L"foo-string");
  326. x = "foo-";
  327. x += ws.c_str(); // const wchar_t* null terminated
  328. PATH_IS(x, L"foo-wstring");
  329. x = "foo-";
  330. x += 'x'; // char
  331. PATH_IS(x, L"foo-x");
  332. x = "foo-";
  333. x += L'x'; // wchar
  334. PATH_IS(x, L"foo-x");
  335. }
  336. // test_observers ------------------------------------------------------------------//
  337. void test_observers()
  338. {
  339. std::cout << "testing observers..." << std::endl;
  340. path p0("abc");
  341. CHECK(p0.native().size() == 3);
  342. CHECK(p0.size() == 3);
  343. CHECK(p0.string() == "abc");
  344. CHECK(p0.string().size() == 3);
  345. CHECK(p0.wstring() == L"abc");
  346. CHECK(p0.wstring().size() == 3);
  347. p0 = "";
  348. CHECK(p0.native().size() == 0);
  349. CHECK(p0.size() == 0);
  350. # ifdef BOOST_WINDOWS_API
  351. path p("abc\\def/ghi");
  352. CHECK(std::wstring(p.c_str()) == L"abc\\def/ghi");
  353. CHECK(p.string() == "abc\\def/ghi");
  354. CHECK(p.wstring() == L"abc\\def/ghi");
  355. CHECK(p.generic_path().string() == "abc/def/ghi");
  356. CHECK(p.generic_string() == "abc/def/ghi");
  357. CHECK(p.generic_wstring() == L"abc/def/ghi");
  358. CHECK(p.generic_string<string>() == "abc/def/ghi");
  359. CHECK(p.generic_string<wstring>() == L"abc/def/ghi");
  360. CHECK(p.generic_string<path::string_type>() == L"abc/def/ghi");
  361. # else // BOOST_POSIX_API
  362. path p("abc\\def/ghi");
  363. CHECK(string(p.c_str()) == "abc\\def/ghi");
  364. CHECK(p.string() == "abc\\def/ghi");
  365. CHECK(p.wstring() == L"abc\\def/ghi");
  366. CHECK(p.generic_path().string() == "abc\\def/ghi");
  367. CHECK(p.generic_string() == "abc\\def/ghi");
  368. CHECK(p.generic_wstring() == L"abc\\def/ghi");
  369. CHECK(p.generic_string<string>() == "abc\\def/ghi");
  370. CHECK(p.generic_string<wstring>() == L"abc\\def/ghi");
  371. CHECK(p.generic_string<path::string_type>() == "abc\\def/ghi");
  372. # endif
  373. }
  374. // test_relationals ----------------------------------------------------------------//
  375. void test_relationals()
  376. {
  377. std::cout << "testing relationals..." << std::endl;
  378. boost::hash<path> hash;
  379. # ifdef BOOST_WINDOWS_API
  380. // this is a critical use case to meet user expectations
  381. CHECK(path("c:\\abc") == path("c:/abc"));
  382. CHECK(hash(path("c:\\abc")) == hash(path("c:/abc")));
  383. # endif
  384. const path p("bar");
  385. const path p2("baz");
  386. CHECK(!(p < p));
  387. CHECK(p < p2);
  388. CHECK(!(p2 < p));
  389. CHECK(p < "baz");
  390. CHECK(p < string("baz"));
  391. CHECK(p < L"baz");
  392. CHECK(p < wstring(L"baz"));
  393. CHECK(!("baz" < p));
  394. CHECK(!(string("baz") < p));
  395. CHECK(!(L"baz" < p));
  396. CHECK(!(wstring(L"baz") < p));
  397. CHECK(p == p);
  398. CHECK(!(p == p2));
  399. CHECK(!(p2 == p));
  400. CHECK(p2 == "baz");
  401. CHECK(p2 == string("baz"));
  402. CHECK(p2 == L"baz");
  403. CHECK(p2 == wstring(L"baz"));
  404. CHECK("baz" == p2);
  405. CHECK(string("baz") == p2);
  406. CHECK(L"baz" == p2);
  407. CHECK(wstring(L"baz") == p2);
  408. CHECK(hash(p) == hash(p));
  409. CHECK(hash(p) != hash(p2)); // Not strictly required, but desirable
  410. CHECK(!(p != p));
  411. CHECK(p != p2);
  412. CHECK(p2 != p);
  413. CHECK(p <= p);
  414. CHECK(p <= p2);
  415. CHECK(!(p2 <= p));
  416. CHECK(!(p > p));
  417. CHECK(!(p > p2));
  418. CHECK(p2 > p);
  419. CHECK(p >= p);
  420. CHECK(!(p >= p2));
  421. CHECK(p2 >= p);
  422. }
  423. // test_inserter_and_extractor -----------------------------------------------------//
  424. void test_inserter_and_extractor()
  425. {
  426. std::cout << "testing inserter and extractor..." << std::endl;
  427. path p1("foo bar"); // verify space in path roundtrips per ticket #3863
  428. path p2;
  429. std::stringstream ss;
  430. CHECK(p1 != p2);
  431. ss << p1;
  432. ss >> p2;
  433. CHECK(p1 == p2);
  434. path wp1(L"foo bar");
  435. path wp2;
  436. std::wstringstream wss;
  437. CHECK(wp1 != wp2);
  438. wss << wp1;
  439. wss >> wp2;
  440. CHECK(wp1 == wp2);
  441. }
  442. // test_other_non_members ----------------------------------------------------------//
  443. void test_other_non_members()
  444. {
  445. std::cout << "testing other_non_members..." << std::endl;
  446. path p1("foo");
  447. path p2("bar");
  448. // operator /
  449. CHECK(p1 / p2 == path("foo/bar").make_preferred());
  450. CHECK("foo" / p2 == path("foo/bar").make_preferred());
  451. CHECK(L"foo" / p2 == path("foo/bar").make_preferred());
  452. CHECK(string("foo") / p2 == path("foo/bar").make_preferred());
  453. CHECK(wstring(L"foo") / p2 == path("foo/bar").make_preferred());
  454. CHECK(p1 / "bar" == path("foo/bar").make_preferred());
  455. CHECK(p1 / L"bar" == path("foo/bar").make_preferred());
  456. CHECK(p1 / string("bar") == path("foo/bar").make_preferred());
  457. CHECK(p1 / wstring(L"bar") == path("foo/bar").make_preferred());
  458. swap(p1, p2);
  459. CHECK(p1 == "bar");
  460. CHECK(p2 == "foo");
  461. CHECK(!path("").filename_is_dot());
  462. CHECK(!path("").filename_is_dot_dot());
  463. CHECK(!path("..").filename_is_dot());
  464. CHECK(!path(".").filename_is_dot_dot());
  465. CHECK(!path("...").filename_is_dot_dot());
  466. CHECK(path(".").filename_is_dot());
  467. CHECK(path("..").filename_is_dot_dot());
  468. CHECK(path("/.").filename_is_dot());
  469. CHECK(path("/..").filename_is_dot_dot());
  470. CHECK(!path("a.").filename_is_dot());
  471. CHECK(!path("a..").filename_is_dot_dot());
  472. // edge cases
  473. CHECK(path("foo/").filename() == path("."));
  474. CHECK(path("foo/").filename_is_dot());
  475. CHECK(path("/").filename() == path("/"));
  476. CHECK(!path("/").filename_is_dot());
  477. # ifdef BOOST_WINDOWS_API
  478. CHECK(path("c:.").filename() == path("."));
  479. CHECK(path("c:.").filename_is_dot());
  480. CHECK(path("c:/").filename() == path("/"));
  481. CHECK(!path("c:\\").filename_is_dot());
  482. # else
  483. CHECK(path("c:.").filename() == path("c:."));
  484. CHECK(!path("c:.").filename_is_dot());
  485. CHECK(path("c:/").filename() == path("."));
  486. CHECK(path("c:/").filename_is_dot());
  487. # endif
  488. // check that the implementation code to make the edge cases above work right
  489. // doesn't cause some non-edge cases to fail
  490. CHECK(path("c:").filename() != path("."));
  491. CHECK(!path("c:").filename_is_dot());
  492. // examples from reference.html
  493. std::cout << path(".").filename_is_dot(); // outputs 1
  494. std::cout << path("/.").filename_is_dot(); // outputs 1
  495. std::cout << path("foo/.").filename_is_dot(); // outputs 1
  496. std::cout << path("foo/").filename_is_dot(); // outputs 1
  497. std::cout << path("/").filename_is_dot(); // outputs 0
  498. std::cout << path("/foo").filename_is_dot(); // outputs 0
  499. std::cout << path("/foo.").filename_is_dot(); // outputs 0
  500. std::cout << path("..").filename_is_dot(); // outputs 0
  501. cout << std::endl;
  502. }
  503. // // test_modifiers ------------------------------------------------------------------//
  504. //
  505. // void test_modifiers()
  506. // {
  507. // std::cout << "testing modifiers..." << std::endl;
  508. //
  509. // }
  510. // test_iterators ------------------------------------------------------------------//
  511. void test_iterators()
  512. {
  513. std::cout << "testing iterators..." << std::endl;
  514. path p1;
  515. CHECK(p1.begin() == p1.end());
  516. path p2("/");
  517. CHECK(p2.begin() != p2.end());
  518. CHECK(*p2.begin() == "/");
  519. CHECK(++p2.begin() == p2.end());
  520. path p3("foo/bar/baz");
  521. path::iterator it(p3.begin());
  522. CHECK(p3.begin() != p3.end());
  523. CHECK(*it == "foo");
  524. CHECK(*++it == "bar");
  525. CHECK(*++it == "baz");
  526. CHECK(*--it == "bar");
  527. CHECK(*--it == "foo");
  528. CHECK(*++it == "bar");
  529. CHECK(*++it == "baz");
  530. CHECK(++it == p3.end());
  531. }
  532. // test_reverse_iterators ----------------------------------------------------------//
  533. void test_reverse_iterators()
  534. {
  535. std::cout << "testing reverse_iterators..." << std::endl;
  536. path p1;
  537. CHECK(p1.rbegin() == p1.rend());
  538. path p2("/");
  539. CHECK(p2.rbegin() != p2.rend());
  540. CHECK(*p2.rbegin() == "/");
  541. CHECK(++p2.rbegin() == p2.rend());
  542. path p3("foo/bar/baz");
  543. path::reverse_iterator it(p3.rbegin());
  544. CHECK(p3.rbegin() != p3.rend());
  545. CHECK(*it == "baz");
  546. CHECK(*++it == "bar");
  547. CHECK(*++it == "foo");
  548. CHECK(*--it == "bar");
  549. CHECK(*--it == "baz");
  550. CHECK(*++it == "bar");
  551. CHECK(*++it == "foo");
  552. CHECK(++it == p3.rend());
  553. }
  554. // test_modifiers ------------------------------------------------------------------//
  555. void test_modifiers()
  556. {
  557. std::cout << "testing modifiers..." << std::endl;
  558. CHECK(path("").remove_filename() == "");
  559. CHECK(path("foo").remove_filename() == "");
  560. CHECK(path("/foo").remove_filename() == "/");
  561. CHECK(path("foo/bar").remove_filename() == "foo");
  562. BOOST_TEST_EQ(path("foo/bar/").remove_filename(), path("foo/bar"));
  563. BOOST_TEST_EQ(path(".").remove_filename(), path(""));
  564. BOOST_TEST_EQ(path("./.").remove_filename(), path("."));
  565. BOOST_TEST_EQ(path("/.").remove_filename(), path("/"));
  566. BOOST_TEST_EQ(path("..").remove_filename(), path(""));
  567. BOOST_TEST_EQ(path("../..").remove_filename(), path(".."));
  568. BOOST_TEST_EQ(path("/..").remove_filename(), path("/"));
  569. }
  570. // test_decompositions -------------------------------------------------------------//
  571. void test_decompositions()
  572. {
  573. std::cout << "testing decompositions..." << std::endl;
  574. CHECK(path("").root_name().string() == "");
  575. CHECK(path("foo").root_name().string() == "");
  576. CHECK(path("/").root_name().string() == "");
  577. CHECK(path("/foo").root_name().string() == "");
  578. CHECK(path("//netname").root_name().string() == "//netname");
  579. CHECK(path("//netname/foo").root_name().string() == "//netname");
  580. CHECK(path("").root_directory().string() == "");
  581. CHECK(path("foo").root_directory().string() == "");
  582. CHECK(path("/").root_directory().string() == "/");
  583. CHECK(path("/foo").root_directory().string() == "/");
  584. CHECK(path("//netname").root_directory().string() == "");
  585. CHECK(path("//netname/foo").root_directory().string() == "/");
  586. CHECK(path("").root_path().string() == "");
  587. CHECK(path("/").root_path().string() == "/");
  588. CHECK(path("/foo").root_path().string() == "/");
  589. CHECK(path("//netname").root_path().string() == "//netname");
  590. CHECK(path("//netname/foo").root_path().string() == "//netname/");
  591. # ifdef BOOST_WINDOWS_API
  592. CHECK(path("c:/foo").root_path().string() == "c:/");
  593. # endif
  594. CHECK(path("").relative_path().string() == "");
  595. CHECK(path("/").relative_path().string() == "");
  596. CHECK(path("/foo").relative_path().string() == "foo");
  597. CHECK(path("").parent_path().string() == "");
  598. CHECK(path("/").parent_path().string() == "");
  599. CHECK(path("/foo").parent_path().string() == "/");
  600. CHECK(path("/foo/bar").parent_path().string() == "/foo");
  601. CHECK(path("/foo/bar/baz.zoo").filename().string() == "baz.zoo");
  602. CHECK(path("/foo/bar/baz.zoo").stem().string() == "baz");
  603. CHECK(path("/foo/bar.woo/baz").stem().string() == "baz");
  604. CHECK(path("foo.bar.baz.tar.bz2").extension().string() == ".bz2");
  605. CHECK(path("/foo/bar/baz.zoo").extension().string() == ".zoo");
  606. CHECK(path("/foo/bar.woo/baz").extension().string() == "");
  607. }
  608. // test_queries --------------------------------------------------------------------//
  609. void test_queries()
  610. {
  611. std::cout << "testing queries..." << std::endl;
  612. path p1("");
  613. path p2("//netname/foo.doo");
  614. CHECK(p1.empty());
  615. CHECK(!p1.has_root_path());
  616. CHECK(!p1.has_root_name());
  617. CHECK(!p1.has_root_directory());
  618. CHECK(!p1.has_relative_path());
  619. CHECK(!p1.has_parent_path());
  620. CHECK(!p1.has_filename());
  621. CHECK(!p1.has_stem());
  622. CHECK(!p1.has_extension());
  623. CHECK(!p1.is_absolute());
  624. CHECK(p1.is_relative());
  625. CHECK(!p2.empty());
  626. CHECK(p2.has_root_path());
  627. CHECK(p2.has_root_name());
  628. CHECK(p2.has_root_directory());
  629. CHECK(p2.has_relative_path());
  630. CHECK(p2.has_parent_path());
  631. CHECK(p2.has_filename());
  632. CHECK(p2.has_stem());
  633. CHECK(p2.has_extension());
  634. CHECK(p2.is_absolute());
  635. CHECK(!p2.is_relative());
  636. }
  637. // test_imbue_locale ---------------------------------------------------------------//
  638. void test_imbue_locale()
  639. {
  640. std::cout << "testing imbue locale..." << std::endl;
  641. // weak test case for before/after states since we don't know what characters the
  642. // default locale accepts.
  643. path before("abc");
  644. // So that tests are run with known encoding, use Boost UTF-8 codecvt
  645. // \u2722 and \xE2\x9C\xA2 are UTF-16 and UTF-8 FOUR TEARDROP-SPOKED ASTERISK
  646. std::locale global_loc = std::locale();
  647. std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet);
  648. std::cout << " imbuing locale ..." << std::endl;
  649. std::locale old_loc = path::imbue(loc);
  650. std::cout << " testing with the imbued locale ..." << std::endl;
  651. path p2("\xE2\x9C\xA2");
  652. CHECK(p2.wstring().size() == 1);
  653. CHECK(p2.wstring()[0] == 0x2722);
  654. std::cout << " imbuing the original locale ..." << std::endl;
  655. path::imbue(old_loc);
  656. std::cout << " testing with the original locale ..." << std::endl;
  657. path after("abc");
  658. CHECK(before == after);
  659. std::cout << " locale testing complete" << std::endl;
  660. }
  661. // test_codecvt_argument -----------------------------------------------------------//
  662. void test_codecvt_argument()
  663. {
  664. std::cout << "testing codecvt arguments..." << std::endl;
  665. const char * c1 = "a1";
  666. const std::string s1(c1);
  667. const std::wstring ws1(L"b2"); // off-by-one mimics test_codecvt
  668. const std::string s2("y8");
  669. const std::wstring ws2(L"z9");
  670. test_codecvt cvt; // produces off-by-one values that will always differ from
  671. // the system's default locale codecvt facet
  672. int t = 0;
  673. // constructors
  674. std::cout << " constructors test " << ++t << std::endl;
  675. path p(c1, cvt);
  676. NATIVE_IS(p, s1, ws1);
  677. std::cout << " test " << ++t << std::endl;
  678. path p1(s1.begin(), s1.end(), cvt);
  679. NATIVE_IS(p1, s1, ws1);
  680. std::cout << " test " << ++t << std::endl;
  681. path p2(ws2, cvt);
  682. NATIVE_IS(p2, s2, ws2);
  683. std::cout << " test " << ++t << std::endl;
  684. path p3(ws2.begin(), ws2.end(), cvt);
  685. NATIVE_IS(p3, s2, ws2);
  686. // path p2(p1, cvt); // fails to compile, and that is OK
  687. // assigns
  688. p1.clear();
  689. std::cout << " assigns test " << ++t << std::endl;
  690. p1.assign(s1,cvt);
  691. NATIVE_IS(p1, s1, ws1);
  692. p1.clear();
  693. std::cout << " test " << ++t << std::endl;
  694. p1.assign(s1.begin(), s1.end(), cvt);
  695. NATIVE_IS(p1, s1, ws1);
  696. // p1.assign(p, cvt); // fails to compile, and that is OK
  697. // appends
  698. p1.clear();
  699. std::cout << " appends test " << ++t << std::endl;
  700. p1.append(s1,cvt);
  701. NATIVE_IS(p1, s1, ws1);
  702. p1.clear();
  703. std::cout << " test " << ++t << std::endl;
  704. p1.append(s1.begin(), s1.end(), cvt);
  705. NATIVE_IS(p1, s1, ws1);
  706. // p1.append(p, cvt); // fails to compile, and that is OK
  707. // native observers
  708. std::cout << " native observers test " << ++t << std::endl;
  709. CHECK(p.string<std::string>(cvt) == s1);
  710. std::cout << " test " << ++t << std::endl;
  711. CHECK(p.string(cvt) == s1);
  712. std::cout << " test " << ++t << std::endl;
  713. CHECK(p.string<std::wstring>(cvt) == ws1);
  714. std::cout << " test " << ++t << std::endl;
  715. CHECK(p.wstring(cvt) == ws1);
  716. // generic observers
  717. std::cout << " generic observers test " << ++t << std::endl;
  718. CHECK(p.generic_string<std::string>(cvt) == s1);
  719. std::cout << " test " << ++t << std::endl;
  720. CHECK(p.generic_string(cvt) == s1);
  721. std::cout << " test " << ++t << std::endl;
  722. CHECK(p.generic_string<std::wstring>(cvt) == ws1);
  723. std::cout << " test " << ++t << std::endl;
  724. CHECK(p.generic_wstring(cvt) == ws1);
  725. std::cout << " codecvt arguments testing complete" << std::endl;
  726. }
  727. // test_overloads ------------------------------------------------------------------//
  728. void test_overloads()
  729. {
  730. std::cout << "testing overloads..." << std::endl;
  731. std::string sto("hello");
  732. const char a[] = "goodbye";
  733. path p1(sto);
  734. path p2(sto.c_str());
  735. path p3(a);
  736. path p4("foo");
  737. std::wstring wsto(L"hello");
  738. const wchar_t wa[] = L"goodbye";
  739. path wp1(wsto);
  740. path wp2(wsto.c_str());
  741. path wp3(wa);
  742. path wp4(L"foo");
  743. }
  744. // test_error_handling -------------------------------------------------------------//
  745. class error_codecvt
  746. : public std::codecvt< wchar_t, char, std::mbstate_t >
  747. {
  748. public:
  749. explicit error_codecvt()
  750. : std::codecvt<wchar_t, char, std::mbstate_t>() {}
  751. protected:
  752. virtual bool do_always_noconv() const throw() { return false; }
  753. virtual int do_encoding() const throw() { return 0; }
  754. virtual std::codecvt_base::result do_in(std::mbstate_t&,
  755. const char*, const char*, const char*&,
  756. wchar_t*, wchar_t*, wchar_t*&) const
  757. {
  758. static std::codecvt_base::result r = std::codecvt_base::noconv;
  759. if (r == std::codecvt_base::partial) r = std::codecvt_base::error;
  760. else if (r == std::codecvt_base::error) r = std::codecvt_base::noconv;
  761. else r = std::codecvt_base::partial;
  762. return r;
  763. }
  764. virtual std::codecvt_base::result do_out(std::mbstate_t &,
  765. const wchar_t*, const wchar_t*, const wchar_t*&,
  766. char*, char*, char*&) const
  767. {
  768. static std::codecvt_base::result r = std::codecvt_base::noconv;
  769. if (r == std::codecvt_base::partial) r = std::codecvt_base::error;
  770. else if (r == std::codecvt_base::error) r = std::codecvt_base::noconv;
  771. else r = std::codecvt_base::partial;
  772. return r;
  773. }
  774. virtual std::codecvt_base::result do_unshift(std::mbstate_t&,
  775. char*, char*, char* &) const { return ok; }
  776. virtual int do_length(std::mbstate_t &,
  777. const char*, const char*, std::size_t) const { return 0; }
  778. virtual int do_max_length() const throw () { return 0; }
  779. };
  780. void test_error_handling()
  781. {
  782. std::cout << "testing error handling..." << std::endl;
  783. std::locale global_loc = std::locale();
  784. std::locale loc(global_loc, new error_codecvt);
  785. std::cout << " imbuing error locale ..." << std::endl;
  786. std::locale old_loc = path::imbue(loc);
  787. // These tests rely on a path constructor that fails in the locale conversion.
  788. // Thus construction has to call codecvt. Force that by using a narrow string
  789. // for Windows, and a wide string for POSIX.
  790. # ifdef BOOST_WINDOWS_API
  791. # define STRING_FOO_ "foo"
  792. # else
  793. # define STRING_FOO_ L"foo"
  794. # endif
  795. {
  796. std::cout << " testing std::codecvt_base::partial error..." << std::endl;
  797. bool exception_thrown (false);
  798. try { path(STRING_FOO_); }
  799. catch (const bs::system_error & ex)
  800. {
  801. exception_thrown = true;
  802. BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::partial,
  803. fs::codecvt_error_category()));
  804. }
  805. catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
  806. BOOST_TEST(exception_thrown);
  807. }
  808. {
  809. std::cout << " testing std::codecvt_base::error error..." << std::endl;
  810. bool exception_thrown (false);
  811. try { path(STRING_FOO_); }
  812. catch (const bs::system_error & ex)
  813. {
  814. exception_thrown = true;
  815. BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::error,
  816. fs::codecvt_error_category()));
  817. }
  818. catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
  819. BOOST_TEST(exception_thrown);
  820. }
  821. {
  822. std::cout << " testing std::codecvt_base::noconv error..." << std::endl;
  823. bool exception_thrown (false);
  824. try { path(STRING_FOO_); }
  825. catch (const bs::system_error & ex)
  826. {
  827. exception_thrown = true;
  828. BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::noconv,
  829. fs::codecvt_error_category()));
  830. }
  831. catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
  832. BOOST_TEST(exception_thrown);
  833. }
  834. std::cout << " restoring original locale ..." << std::endl;
  835. path::imbue(old_loc);
  836. std::cout << " testing error handling complete" << std::endl;
  837. }
  838. # if 0
  839. // // test_locales --------------------------------------------------------------------//
  840. //
  841. // void test_locales()
  842. // {
  843. // std::cout << "testing locales..." << std::endl;
  844. //
  845. // }
  846. // test_user_supplied_type ---------------------------------------------------------//
  847. typedef std::basic_string<int> user_string;
  848. } // unnamed namespace
  849. namespace boost
  850. {
  851. namespace filesystem
  852. {
  853. namespace path_traits
  854. {
  855. template<> struct is_iterator<const user_string::value_type *> { static const bool value = true; };
  856. template<> struct is_iterator<user_string::value_type *> { static const bool value = true; };
  857. template<> struct is_iterator<user_string::iterator> { static const bool value = true; };
  858. template<> struct is_iterator<user_string::const_iterator> { static const bool value = true; };
  859. template<> struct is_container<user_string> { static const bool value = true; };
  860. template<>
  861. void append<user_string::value_type>(const user_string::value_type * begin,
  862. const user_string::value_type * end, string_type & target, system::error_code & ec)
  863. {
  864. for (; begin != end && *begin; ++begin)
  865. target += *begin + 1; // change so that results distinguishable from char cvts
  866. }
  867. # ifdef __GNUC__
  868. // This specialization shouldn't be needed, and VC++, Intel, and others work
  869. // fine without it. But gcc 4.3.2, and presumably other versions, need it.
  870. template<>
  871. void append<user_string::value_type>(const user_string::value_type * begin,
  872. string_type & target, system::error_code & ec)
  873. {
  874. path_traits::append<user_string::value_type>(begin,
  875. static_cast<const user_string::value_type *>(0), target, ec);
  876. }
  877. # endif
  878. template<>
  879. user_string convert<user_string>(const string_type & source,
  880. system::error_code & ec)
  881. {
  882. user_string temp;
  883. for (string_type::const_iterator it = source.begin();
  884. it != source.end(); ++it)
  885. temp += *it - 1;
  886. return temp;
  887. }
  888. } // namespace path_traits
  889. } // namespace filesystem
  890. } // namespace boost
  891. namespace
  892. {
  893. void test_user_supplied_type()
  894. {
  895. std::cout << "testing user supplied type..." << std::endl;
  896. user_string::value_type usr_c_str[] = { 'a', 'b', 'c', 0 };
  897. user_string usr(usr_c_str);
  898. path p1(usr.c_str());
  899. CHECK(p1 == path("bcd"));
  900. CHECK(p1 == "bcd");
  901. user_string s1(p1.string<user_string>());
  902. CHECK(s1 == usr);
  903. }
  904. # endif
  905. inline const char* macro_value(const char* name, const char* value)
  906. {
  907. static const char* no_value = "[no value]";
  908. static const char* not_defined = "[not defined]";
  909. //if (0 != strcmp(name, value + 1)) // macro is defined
  910. //{
  911. // if (value[1])
  912. // return value;
  913. // else
  914. // return no_value;
  915. //}
  916. //return not_defined;
  917. return 0 == strcmp(name, value + 1)
  918. ? not_defined
  919. : (value[1] ? value : no_value);
  920. }
  921. #define BOOST_MACRO_VALUE(X) macro_value(#X, BOOST_STRINGIZE(=X))
  922. } // unnamed namespace
  923. //--------------------------------------------------------------------------------------//
  924. // //
  925. // main //
  926. // //
  927. //--------------------------------------------------------------------------------------//
  928. int test_main(int, char*[])
  929. {
  930. // document state of critical macros
  931. #ifdef BOOST_POSIX_API
  932. cout << "BOOST_POSIX_API" << endl;
  933. BOOST_TEST(path::preferred_separator == '/');
  934. #endif
  935. #ifdef BOOST_WINDOWS_API
  936. cout << "BOOST_WINDOWS_API" << endl;
  937. BOOST_TEST(path::preferred_separator == '\\');
  938. #endif
  939. cout << "BOOST_FILESYSTEM_DECL "
  940. << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_DECL) << endl;
  941. //#ifdef BOOST_FILESYSTEM_DECL
  942. // cout << "BOOST_FILESYSTEM_DECL is defined as "
  943. // << BOOST_STRINGIZE(BOOST_FILESYSTEM_DECL) << endl;
  944. //#else
  945. // cout << "BOOST_FILESYSTEM_DECL is not defined" << endl;
  946. //#endif
  947. l.push_back('s');
  948. l.push_back('t');
  949. l.push_back('r');
  950. l.push_back('i');
  951. l.push_back('n');
  952. l.push_back('g');
  953. wl.push_back(L'w');
  954. wl.push_back(L's');
  955. wl.push_back(L't');
  956. wl.push_back(L'r');
  957. wl.push_back(L'i');
  958. wl.push_back(L'n');
  959. wl.push_back(L'g');
  960. v.push_back('f');
  961. v.push_back('u');
  962. v.push_back('z');
  963. wv.push_back(L'w');
  964. wv.push_back(L'f');
  965. wv.push_back(L'u');
  966. wv.push_back(L'z');
  967. test_overloads();
  968. test_constructors();
  969. test_assignments();
  970. test_move_construction_and_assignment();
  971. test_appends();
  972. test_concats();
  973. test_modifiers();
  974. test_observers();
  975. test_relationals();
  976. test_inserter_and_extractor();
  977. test_other_non_members();
  978. test_iterators();
  979. test_reverse_iterators();
  980. test_decompositions();
  981. test_queries();
  982. test_imbue_locale();
  983. test_codecvt_argument();
  984. test_error_handling();
  985. #if 0
  986. test_user_supplied_type();
  987. #endif
  988. std::string foo("\\abc");
  989. const char* bar = "/abc";
  990. if (foo == bar)
  991. cout << "unintended consequence\n";
  992. return ::boost::report_errors();
  993. }