1 /** 2 * @file unit-cppapi-vfs.cc 3 * 4 * @section LICENSE 5 * 6 * The MIT License 7 * 8 * @copyright Copyright (c) 2017-2021 TileDB Inc. 9 * 10 * Permission is hereby granted, free of charge, to any person obtaining a copy 11 * of this software and associated documentation files (the "Software"), to deal 12 * in the Software without restriction, including without limitation the rights 13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 * copies of the Software, and to permit persons to whom the Software is 15 * furnished to do so, subject to the following conditions: 16 * 17 * The above copyright notice and this permission notice shall be included in 18 * all copies or substantial portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 * THE SOFTWARE. 27 * 28 * @section DESCRIPTION 29 * 30 * Tests the C++ API for the VFS functionality. 31 */ 32 33 #include "catch.hpp" 34 #include "tiledb/sm/cpp_api/tiledb" 35 36 #ifdef _WIN32 37 #include "tiledb/sm/filesystem/win.h" 38 #else 39 #include "tiledb/sm/filesystem/posix.h" 40 #endif 41 42 TEST_CASE("C++ API: Test VFS ls", "[cppapi][cppapi-vfs][cppapi-vfs-ls]") { 43 using namespace tiledb; 44 Context ctx; 45 VFS vfs(ctx); 46 #ifdef _WIN32 47 std::string path = sm::Win::current_dir() + "\\vfs_test\\"; 48 #else 49 std::string path = 50 std::string("file://") + sm::Posix::current_dir() + "/vfs_test/"; 51 #endif 52 53 // Clean up 54 if (vfs.is_dir(path)) 55 vfs.remove_dir(path); 56 57 std::string dir = path + "ls_dir"; 58 std::string file = dir + "/file"; 59 std::string file2 = dir + "/file2"; 60 std::string subdir = dir + "/subdir"; 61 std::string subdir2 = dir + "/subdir2"; 62 std::string subdir_file = subdir + "/file"; 63 std::string subdir_file2 = subdir2 + "/file2"; 64 65 // Create directories and files 66 vfs.create_dir(path); 67 vfs.create_dir(dir); 68 vfs.create_dir(subdir); 69 vfs.create_dir(subdir2); 70 vfs.touch(file); 71 vfs.touch(file2); 72 vfs.touch(subdir_file); 73 vfs.touch(subdir_file2); 74 75 // List 76 std::vector<std::string> children = vfs.ls(dir); 77 78 #ifdef _WIN32 79 // Normalization only for Windows 80 file = tiledb::sm::Win::uri_from_path(file); 81 file2 = tiledb::sm::Win::uri_from_path(file2); 82 subdir = tiledb::sm::Win::uri_from_path(subdir); 83 subdir2 = tiledb::sm::Win::uri_from_path(subdir2); 84 #endif 85 86 // Check results 87 std::sort(children.begin(), children.end()); 88 REQUIRE(children.size() == 4); 89 CHECK(children[0] == file); 90 CHECK(children[1] == file2); 91 CHECK(children[2] == subdir); 92 CHECK(children[3] == subdir2); 93 94 // Clean up 95 vfs.remove_dir(path); 96 } 97 98 TEST_CASE( 99 "C++ API: Test VFS dir size", "[cppapi][cppapi-vfs][cppapi-vfs-dir-size]") { 100 using namespace tiledb; 101 Context ctx; 102 VFS vfs(ctx); 103 104 #ifdef _WIN32 105 std::string path = sm::Win::current_dir() + "\\vfs_test\\"; 106 #else 107 std::string path = 108 std::string("file://") + sm::Posix::current_dir() + "/vfs_test/"; 109 #endif 110 111 // Clean up 112 if (vfs.is_dir(path)) 113 vfs.remove_dir(path); 114 115 std::string dir = path + "ls_dir"; 116 std::string file = dir + "/file"; 117 std::string file2 = dir + "/file2"; 118 std::string subdir = dir + "/subdir"; 119 std::string subdir2 = dir + "/subdir2"; 120 std::string subdir_file = subdir + "/file"; 121 std::string subdir_file2 = subdir + "/file2"; 122 123 // Create directories and files 124 vfs.create_dir(path); 125 vfs.create_dir(dir); 126 vfs.create_dir(subdir); 127 vfs.create_dir(subdir2); 128 vfs.touch(file); 129 vfs.touch(file2); 130 vfs.touch(subdir_file); 131 vfs.touch(subdir_file2); 132 133 // Write to file 134 tiledb::VFS::filebuf fbuf(vfs); 135 fbuf.open(file, std::ios::out); 136 std::ostream os(&fbuf); 137 std::string s1 = "abcd"; 138 os.write(s1.data(), s1.size()); 139 fbuf.close(); 140 141 // Write to file2 142 fbuf.open(file2, std::ios::out); 143 std::ostream os2(&fbuf); 144 std::string s2 = "abcdefgh"; 145 os2.write(s2.data(), s2.size()); 146 fbuf.close(); 147 148 // Write to subdir_file 149 fbuf.open(subdir_file, std::ios::out); 150 std::ostream os3(&fbuf); 151 std::string s3 = "a"; 152 os3.write(s3.data(), s3.size()); 153 fbuf.close(); 154 155 // Write to subdir_file2 156 fbuf.open(subdir_file2, std::ios::out); 157 std::ostream os4(&fbuf); 158 std::string s4 = "ab"; 159 os4.write(s4.data(), s4.size()); 160 fbuf.close(); 161 162 // Get directory size 163 auto dir_size = vfs.dir_size(path); 164 CHECK(dir_size == 15); 165 166 // Clean up 167 vfs.remove_dir(path); 168 } 169 170 TEST_CASE( 171 "C++ API: Test VFS copy file", 172 "[cppapi][cppapi-vfs][cppapi-vfs-copy-file]") { 173 using namespace tiledb; 174 Context ctx; 175 VFS vfs(ctx); 176 177 #ifndef _WIN32 178 std::string path = 179 std::string("file://") + sm::Posix::current_dir() + "/vfs_test/"; 180 181 // Clean up 182 if (vfs.is_dir(path)) 183 vfs.remove_dir(path); 184 185 std::string dir = path + "ls_dir"; 186 std::string file = dir + "/file"; 187 std::string file2 = dir + "/file2"; 188 189 // Create directories and files 190 vfs.create_dir(path); 191 vfs.create_dir(dir); 192 vfs.touch(file); 193 194 // Write to file 195 tiledb::VFS::filebuf fbuf(vfs); 196 fbuf.open(file, std::ios::out); 197 std::ostream os(&fbuf); 198 std::string s1 = "abcd"; 199 os.write(s1.data(), s1.size()); 200 201 // Copy file when running on POSIX 202 vfs.copy_file(file, file2); 203 REQUIRE(vfs.is_file(file2)); 204 205 fbuf.open(file, std::ios::in); 206 std::istream is1(&fbuf); 207 if (!is1.good()) { 208 std::cerr << "Error opening file.\n"; 209 return; 210 } 211 std::string s2; 212 s2.resize(vfs.file_size(file)); 213 is1.read((char*)s2.data(), vfs.file_size(file)); 214 fbuf.close(); 215 216 fbuf.open(file2, std::ios::in); 217 std::istream is2(&fbuf); 218 if (!is2.good()) { 219 std::cerr << "Error opening file.\n"; 220 return; 221 } 222 std::string s3; 223 s3.resize(vfs.file_size(file2)); 224 is2.read((char*)s3.data(), vfs.file_size(file2)); 225 fbuf.close(); 226 227 REQUIRE(s2 == s3); 228 229 // Clean up 230 vfs.remove_dir(path); 231 232 #endif 233 } 234 235 TEST_CASE( 236 "C++ API: Test VFS copy directory", 237 "[cppapi][cppapi-vfs][cppapi-vfs-copy-dir]") { 238 using namespace tiledb; 239 Context ctx; 240 VFS vfs(ctx); 241 242 #ifndef _WIN32 243 std::string path = 244 std::string("file://") + sm::Posix::current_dir() + "/vfs_test/"; 245 246 // Clean up 247 if (vfs.is_dir(path)) 248 vfs.remove_dir(path); 249 250 std::string dir = path + "ls_dir"; 251 std::string dir2 = path + "ls_dir2"; 252 std::string file = dir + "/file"; 253 std::string file2 = dir + "/file2"; 254 std::string subdir = dir + "/subdir"; 255 std::string subdir2 = dir + "/subdir2"; 256 std::string sub_subdir = subdir + "/subdir"; 257 std::string subdir_file = subdir + "/file"; 258 std::string subdir_file2 = subdir + "/file2"; 259 std::string sub_subdir_file = sub_subdir + "/file"; 260 261 std::string file3 = dir2 + "/file"; 262 std::string file4 = dir2 + "/file2"; 263 std::string subdir3 = dir2 + "/subdir"; 264 std::string subdir4 = dir2 + "/subdir2"; 265 std::string sub_subdir2 = subdir3 + "/subdir"; 266 std::string subdir_file3 = subdir3 + "/file"; 267 std::string subdir_file4 = subdir3 + "/file2"; 268 std::string sub_subdir_file2 = sub_subdir2 + "/file"; 269 270 // Create directories and files 271 vfs.create_dir(path); 272 vfs.create_dir(dir); 273 vfs.create_dir(subdir); 274 vfs.create_dir(sub_subdir); 275 vfs.create_dir(subdir2); 276 vfs.touch(file); 277 vfs.touch(file2); 278 vfs.touch(subdir_file); 279 vfs.touch(subdir_file2); 280 vfs.touch(sub_subdir_file); 281 282 // Write to files 283 tiledb::VFS::filebuf fbuf(vfs); 284 fbuf.open(file, std::ios::out); 285 std::ostream os(&fbuf); 286 std::string s1 = "abcd"; 287 os.write(s1.data(), s1.size()); 288 289 fbuf.open(file2, std::ios::out); 290 std::ostream os1(&fbuf); 291 std::string s2 = "efgh"; 292 os1.write(s2.data(), s2.size()); 293 294 fbuf.open(subdir_file, std::ios::out); 295 std::ostream os2(&fbuf); 296 std::string s3 = "ijkl"; 297 os2.write(s3.data(), s3.size()); 298 299 fbuf.open(subdir_file2, std::ios::out); 300 std::ostream os3(&fbuf); 301 std::string s4 = "mnop"; 302 os3.write(s4.data(), s4.size()); 303 fbuf.close(); 304 305 fbuf.open(sub_subdir_file, std::ios::out); 306 std::ostream os4(&fbuf); 307 std::string s5 = "qrst"; 308 os3.write(s5.data(), s5.size()); 309 fbuf.close(); 310 311 // Copy directory when running on POSIX 312 vfs.copy_dir(dir, dir2); 313 REQUIRE(vfs.is_dir(dir2)); 314 315 // Check that ls trees are correct 316 // and that all files / dirs exist as expected 317 std::vector<std::string> dir_vector = vfs.ls(dir); 318 std::vector<std::string> dir2_vector = vfs.ls(dir2); 319 while (!dir_vector.empty() || !dir2_vector.empty()) { 320 std::string dir_file_name_abs = dir_vector.front(); 321 std::string dir_file_name = dir_file_name_abs.substr(dir.length() + 1); 322 std::string dir2_file_name_abs = dir2_vector.front(); 323 std::string dir2_file_name = dir2_file_name_abs.substr(dir2.length() + 1); 324 325 if (vfs.is_dir(dir_file_name_abs)) { 326 REQUIRE(vfs.is_dir(dir_file_name_abs)); 327 std::vector<std::string> dir_vector2 = vfs.ls(dir_file_name_abs); 328 dir_vector.insert( 329 dir_vector.end(), dir_vector2.begin(), dir_vector2.end()); 330 } else { 331 REQUIRE(vfs.is_file(dir_file_name_abs)); 332 } 333 if (vfs.is_dir(dir2_file_name_abs)) { 334 REQUIRE(vfs.is_dir(dir2_file_name_abs)); 335 std::vector<std::string> dir2_vector2 = vfs.ls(dir2_file_name_abs); 336 dir2_vector.insert( 337 dir2_vector.end(), dir2_vector2.begin(), dir2_vector2.end()); 338 } else { 339 REQUIRE(vfs.is_file(dir2_file_name_abs)); 340 } 341 REQUIRE(dir_file_name == dir2_file_name); 342 dir_vector.erase(dir_vector.begin()); 343 dir2_vector.erase(dir2_vector.begin()); 344 } 345 346 // Check that files in dir2 are equal to their 347 // corresponding file in dir 348 fbuf.open(file, std::ios::in); 349 std::istream is1(&fbuf); 350 if (!is1.good()) { 351 std::cerr << "Error opening file.\n"; 352 return; 353 } 354 std::string s6; 355 s6.resize(vfs.file_size(file)); 356 is1.read((char*)s6.data(), vfs.file_size(file)); 357 fbuf.close(); 358 fbuf.open(file3, std::ios::in); 359 std::istream is2(&fbuf); 360 if (!is2.good()) { 361 std::cerr << "Error opening file.\n"; 362 return; 363 } 364 std::string s7; 365 s7.resize(vfs.file_size(file3)); 366 is2.read((char*)s7.data(), vfs.file_size(file3)); 367 fbuf.close(); 368 REQUIRE(s6 == s7); 369 370 fbuf.open(file2, std::ios::in); 371 std::istream is3(&fbuf); 372 if (!is3.good()) { 373 std::cerr << "Error opening file.\n"; 374 return; 375 } 376 std::string s8; 377 s8.resize(vfs.file_size(file2)); 378 is3.read((char*)s8.data(), vfs.file_size(file2)); 379 fbuf.close(); 380 fbuf.open(file4, std::ios::in); 381 std::istream is4(&fbuf); 382 if (!is4.good()) { 383 std::cerr << "Error opening file.\n"; 384 return; 385 } 386 std::string s9; 387 s9.resize(vfs.file_size(file4)); 388 is4.read((char*)s9.data(), vfs.file_size(file4)); 389 fbuf.close(); 390 REQUIRE(s8 == s9); 391 392 fbuf.open(subdir_file, std::ios::in); 393 std::istream is5(&fbuf); 394 if (!is5.good()) { 395 std::cerr << "Error opening file.\n"; 396 return; 397 } 398 std::string s10; 399 s10.resize(vfs.file_size(subdir_file)); 400 is5.read((char*)s10.data(), vfs.file_size(subdir_file)); 401 fbuf.close(); 402 fbuf.open(subdir_file3, std::ios::in); 403 std::istream is6(&fbuf); 404 if (!is6.good()) { 405 std::cerr << "Error opening file.\n"; 406 return; 407 } 408 std::string s11; 409 s11.resize(vfs.file_size(subdir_file3)); 410 is6.read((char*)s11.data(), vfs.file_size(subdir_file3)); 411 fbuf.close(); 412 REQUIRE(s10 == s11); 413 414 fbuf.open(subdir_file2, std::ios::in); 415 std::istream is7(&fbuf); 416 if (!is7.good()) { 417 std::cerr << "Error opening file.\n"; 418 return; 419 } 420 std::string s12; 421 s12.resize(vfs.file_size(subdir_file2)); 422 is7.read((char*)s12.data(), vfs.file_size(subdir_file2)); 423 fbuf.close(); 424 fbuf.open(subdir_file4, std::ios::in); 425 std::istream is8(&fbuf); 426 if (!is8.good()) { 427 std::cerr << "Error opening file.\n"; 428 return; 429 } 430 std::string s13; 431 s13.resize(vfs.file_size(subdir_file4)); 432 is8.read((char*)s13.data(), vfs.file_size(subdir_file4)); 433 fbuf.close(); 434 REQUIRE(s12 == s13); 435 436 fbuf.open(sub_subdir_file, std::ios::in); 437 std::istream is9(&fbuf); 438 if (!is9.good()) { 439 std::cerr << "Error opening file.\n"; 440 return; 441 } 442 std::string s14; 443 s14.resize(vfs.file_size(sub_subdir_file)); 444 is9.read((char*)s14.data(), vfs.file_size(sub_subdir_file)); 445 fbuf.close(); 446 fbuf.open(sub_subdir_file2, std::ios::in); 447 std::istream is10(&fbuf); 448 if (!is10.good()) { 449 std::cerr << "Error opening file.\n"; 450 return; 451 } 452 std::string s15; 453 s15.resize(vfs.file_size(sub_subdir_file2)); 454 is10.read((char*)s15.data(), vfs.file_size(sub_subdir_file2)); 455 fbuf.close(); 456 REQUIRE(s14 == s15); 457 458 // Clean up 459 vfs.remove_dir(path); 460 461 #endif 462 }