filesystem_test.cpp
Go to the documentation of this file.
1 #include <catch2/catch_all.hpp>
2 #include <catch2/matchers/catch_matchers_all.hpp>
3 
4 using namespace Catch::Matchers;
5 
6 // Include depthai library
7 #include <cstdio>
8 #if(__cplusplus >= 201703L) || (_MSVC_LANG >= 201703L)
9  #include <filesystem>
10 #endif
11 #include <algorithm>
12 #include <depthai/depthai.hpp>
13 #include <string>
14 
15 #if defined(_WIN32) && defined(_MSC_VER)
16  #define NATIVETYPE std::wstring
17  #define MAKENATIVEx(x) L##x
18  #define MAKENATIVE(x) MAKENATIVEx(x)
19  #define DELETEFILE _wremove
20  #define NATIVELENGTH(x) static_cast<std::wstring>(x).length()
21 #else
22  #define NATIVETYPE std::string
23  #define MAKENATIVE(x) x
24  #define DELETEFILE std::remove
25  #define NATIVELENGTH(x) u8length(static_cast<std::string>(x).c_str())
26 #endif
27 
28 #if defined(__cpp_lib_char8_t)
29  #define U8CHAR char8_t
30  #define U8STRING std::u8string
31 #else
32  #define U8CHAR char
33  #define U8STRING std::string
34 #endif
35 
36 #define PATH1 "C:\\dir1\\file1.txt"
37 #define PATH2 "file2.txt"
38 #define PATH3 "/dir3/dir33/file3.txt"
39 #define PATH4 u8"\u00e4\u00eb\u00ef\u00f6\u00fc\u00e1\u00e9\u00ed\u00f3\u00fa\u00df\u00c6\u002e\u010c\u011a\u0141"
40 #define PATH5 "asdf.nothing"
41 #define FILETEXT "This is a test\n"
42 #if defined(_WIN32) && defined(_MSC_VER)
43  #define LPATH4 L"\u00e4\u00eb\u00ef\u00f6\u00fc\u00e1\u00e9\u00ed\u00f3\u00fa\u00df\u00c6\u002e\u010c\u011a\u0141"
44  #define LPATH5 L"asdf.nothing"
45 #endif
46 
47 template <typename T>
48 int u8length(const T* str) noexcept {
49  int count = 0;
50  for(; *str != 0; ++str) count += ((*str & 0xc0) != 0x80);
51  return count;
52 }
53 
54 template <typename U, typename V>
55 bool equalStrings(const U a, const V b) {
56  return std::equal(a.cbegin(), a.cend(), b.cbegin(), b.cend(), [](const typename U::value_type& first, const typename V::value_type& second) {
57  return *reinterpret_cast<const typename U::value_type*>(&first) == *reinterpret_cast<const typename U::value_type*>(&second);
58  });
59 }
60 
61 TEST_CASE("dai::Path utf-8 and native char set handling") {
62  const dai::Path emptyPath;
63  const dai::Path::string_type emptyString = emptyPath;
64  REQUIRE(emptyString.empty());
65 
66  const dai::Path path1(PATH1);
67  const NATIVETYPE string1(path1);
68  REQUIRE(string1 == MAKENATIVE(PATH1));
69 
70  const dai::Path path2(PATH2);
71  const NATIVETYPE string2(path2);
72  REQUIRE(string2 == MAKENATIVE(PATH2));
73 
74  const dai::Path path3(PATH3);
75  const NATIVETYPE string3(path3);
76  REQUIRE(string3 == MAKENATIVE(PATH3));
77 
78  U8CHAR tmp_name4[L_tmpnam];
79  REQUIRE(std::tmpnam(reinterpret_cast<char*>(&tmp_name4[0])) != nullptr);
80  U8STRING string4(tmp_name4);
81  string4 += PATH4;
82  const dai::Path path4(string4);
83  const dai::Path path4compare(PATH4);
84  REQUIRE(u8length(string4.c_str()) == NATIVELENGTH(path4));
85 
86  REQUIRE_NOTHROW([&]() {
87  std::ofstream file(path4);
88  file.write(FILETEXT, sizeof(FILETEXT) - 1);
89  }());
90  CHECK_NOTHROW([&]() {
91  std::ifstream file(path4, std::ios::binary);
92  if(!file.is_open() || !file.good() || file.bad()) {
93  throw std::runtime_error("file not found or corrupted");
94  }
95  file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
96  const char c1 = file.get();
97  }());
98  DELETEFILE(static_cast<NATIVETYPE>(path4).c_str());
99 
100  auto getBlob = [](const dai::Path& path) -> bool { return !static_cast<NATIVETYPE>(path).empty(); };
101  REQUIRE(getBlob(string4));
102  REQUIRE(getBlob("mypath/myfile.blob"));
103  REQUIRE(getBlob([]() -> std::string { return "mypath/rvalue.blob"; }()));
104 #if defined(_WIN32) && defined(_MSC_VER)
105  REQUIRE(getBlob(L"mywidepath/myfile.blob"));
106  std::wstring move2ndTry(L"move my data on the second try");
107  REQUIRE(getBlob(move2ndTry));
108  REQUIRE(getBlob(std::move(move2ndTry)));
109 
110  const dai::Path path4wide(LPATH4);
111  REQUIRE(equalStrings(path4compare.native(), path4wide.native()));
112  REQUIRE(equalStrings(path4compare.u8string(), path4wide.u8string()));
113 
114  REQUIRE_THROWS_AS(path4.string(), std::range_error);
115 #else
116  REQUIRE_NOTHROW(path4.string());
117 #endif
118 
119  REQUIRE(path3.string().length() == (sizeof(PATH3) - 1));
120  REQUIRE(path3.u8string().length() == (sizeof(PATH3) - 1));
121  REQUIRE(path4.u8string() == string4);
122 
123  auto wrapper = [&getBlob](const dai::Path& path) -> bool { return getBlob(path); };
124  REQUIRE(wrapper("pass dai::Path across functions"));
125 
126  // test with std::filesystem
127 #if defined(__cpp_lib_filesystem)
128  const std::filesystem::path fspath1(PATH1);
129  const std::filesystem::path fspath2(PATH2);
130  const std::filesystem::path fspath3(PATH3);
131  #if defined(__cpp_lib_char8_t)
132  const auto fspath4 = std::filesystem::path(PATH4);
133  #else
134  const auto fspath4 = std::filesystem::u8path(PATH4);
135  #endif
136  REQUIRE(getBlob(fspath1));
137  REQUIRE(getBlob(fspath2));
138  REQUIRE(getBlob(fspath3));
139  REQUIRE(getBlob(fspath4));
140 #endif
141 }
142 
143 TEST_CASE("dai::Path with NN blobs") {
144  U8CHAR osTmpPathname[L_tmpnam];
145  REQUIRE(std::tmpnam(reinterpret_cast<char*>(&osTmpPathname[0])) != nullptr);
146  U8STRING strPath(osTmpPathname);
147  strPath += PATH4;
148  const dai::Path daiPath(strPath);
149 
150  dai::Pipeline pipeline;
151  auto nn = pipeline.create<dai::node::NeuralNetwork>();
152 
153  // attempt to use a non-existing blob at a utf-8 path
154 #if defined(_WIN32) && defined(_MSC_VER)
155  REQUIRE_THROWS_WITH(nn->setBlobPath(PATH4), ContainsSubstring("Cannot load blob") && ContainsSubstring("not convertible"));
156  REQUIRE_THROWS_WITH(nn->setBlobPath(strPath), ContainsSubstring("Cannot load blob") && ContainsSubstring("not convertible"));
157  REQUIRE_THROWS_WITH(nn->setBlobPath(daiPath), ContainsSubstring("Cannot load blob") && ContainsSubstring("not convertible"));
158 #else
159  REQUIRE_THROWS_WITH(nn->setBlobPath(PATH4), ContainsSubstring(std::string("Cannot load blob")) && ContainsSubstring(dai::Path(PATH4).string()));
160  REQUIRE_THROWS_WITH(nn->setBlobPath(strPath),
161  ContainsSubstring("Cannot load blob") && ContainsSubstring(std::string{reinterpret_cast<const char*>(strPath.c_str())}));
162  REQUIRE_THROWS_WITH(nn->setBlobPath(daiPath), ContainsSubstring("Cannot load blob") && ContainsSubstring(daiPath.string()));
163 #endif
164 
165  // use blob at known test path
166  const std::string blobPath(BLOB_PATH);
167  const dai::Path diaPath2(BLOB_PATH);
168  const dai::Path diaPath3(blobPath);
169  const dai::Path diaPath4(diaPath2);
170  REQUIRE_NOTHROW(nn->setBlobPath(BLOB_PATH));
171  nn->getAssetManager().remove("__blob");
172  REQUIRE_NOTHROW(nn->setBlobPath(blobPath));
173  nn->getAssetManager().remove("__blob");
174  REQUIRE_NOTHROW(nn->setBlobPath(diaPath2));
175  nn->getAssetManager().remove("__blob");
176  REQUIRE_NOTHROW(nn->setBlobPath(diaPath3));
177  nn->getAssetManager().remove("__blob");
178  REQUIRE_NOTHROW(nn->setBlobPath(diaPath4));
179  nn->getAssetManager().remove("__blob");
180 
181  // use blob at known test path with std::filesystem
182 #if defined(__cpp_lib_filesystem)
183  std::filesystem::path stdPath(BLOB_PATH);
184  REQUIRE_NOTHROW(nn->setBlobPath(stdPath));
185  nn->getAssetManager().remove("__blob");
186 #endif
187 }
188 
189 TEST_CASE("dai::Path with Device") {
190  const char badfile[] = PATH5;
191  const std::string strBadfile(&badfile[0]);
192  const dai::Path diaBadFile(PATH5);
193  dai::Pipeline pipeline;
194  auto nn = pipeline.create<dai::node::NeuralNetwork>();
195  REQUIRE_NOTHROW(nn->setBlobPath(BLOB_PATH));
196  REQUIRE_THROWS_WITH(dai::Device(pipeline, PATH5), ContainsSubstring(PATH5));
197  REQUIRE_THROWS_WITH(dai::Device(pipeline, &badfile[0]), ContainsSubstring(PATH5));
198  REQUIRE_THROWS_WITH(dai::Device(pipeline, strBadfile), ContainsSubstring(PATH5));
199  REQUIRE_THROWS_WITH(dai::Device(pipeline, diaBadFile), ContainsSubstring(PATH5));
200 
201 #if defined(_WIN32) && defined(_MSC_VER)
202  const wchar_t wideBadfile[] = LPATH5;
203  const std::wstring wstrBadfile(LPATH5);
204  const dai::Path diaFileFromWide(LPATH5);
205  REQUIRE_THROWS_WITH(dai::Device(pipeline, LPATH5), ContainsSubstring(PATH5));
206  REQUIRE_THROWS_WITH(dai::Device(pipeline, &wideBadfile[0]), ContainsSubstring(PATH5));
207  REQUIRE_THROWS_WITH(dai::Device(pipeline, wstrBadfile), ContainsSubstring(PATH5));
208  REQUIRE_THROWS_WITH(dai::Device(pipeline, diaFileFromWide), ContainsSubstring(PATH5));
209 #endif
210 
211 #if defined(__cpp_lib_filesystem)
212  std::filesystem::path stdBadfile(PATH5);
213  REQUIRE_THROWS_WITH(dai::Device(pipeline, stdBadfile), ContainsSubstring(PATH5));
214 #endif
215 
216  dai::Device d(pipeline);
217 }
218 
219 TEST_CASE("dai::Path with CalibrationHandler") {
220  U8CHAR tmpFilename[L_tmpnam];
221  REQUIRE(std::tmpnam(reinterpret_cast<char*>(&tmpFilename[0])) != nullptr);
222  U8STRING strFilename(tmpFilename);
223  strFilename += PATH4;
224  dai::Path daiFilename(strFilename);
225 
226  CHECK_NOTHROW([&]() {
227  dai::Device device;
228  dai::CalibrationHandler deviceCalib = device.readCalibration();
229  deviceCalib.eepromToJsonFile(strFilename);
230  std::ifstream file(daiFilename, std::ios::binary);
231  if(!file.is_open() || !file.good() || file.bad()) {
232  throw std::runtime_error("calibration file not found or corrupted");
233  }
234  file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
235  const char c1 = file.get();
236  }());
237  DELETEFILE(static_cast<NATIVETYPE>(daiFilename).c_str());
238 }
239 
240 TEST_CASE("dai::Path with DeviceBootloader") {
241  const U8CHAR badfile[] = PATH4;
242  const U8STRING strBadfile(&badfile[0]);
243  const dai::Path diaBadfile(PATH4);
244 #if defined(_WIN32) && defined(_MSC_VER)
245  const wchar_t wideBadfile[] = LPATH5;
246  const std::wstring wstrBadfile(LPATH5);
247  const dai::Path diaBadWide(LPATH5);
248 #endif
249 
250  bool found = false;
251  dai::DeviceInfo deviceInfo;
252  std::tie(found, deviceInfo) = dai::DeviceBootloader::getFirstAvailableDevice();
253  if(found) {
254  REQUIRE_NOTHROW([&]() {
255  dai::DeviceBootloader bl(deviceInfo);
256  auto currentBlType = bl.getType();
257  }());
258  REQUIRE_NOTHROW([&]() {
259  dai::DeviceBootloader bl(deviceInfo, false);
260  auto currentBlType = bl.getType();
261  }());
262  REQUIRE_THROWS_WITH(
263  [&]() {
264  dai::DeviceBootloader bl(deviceInfo, &badfile[0]);
265  auto currentBlType = bl.getType();
266  }(),
267  ContainsSubstring("doesn't exist"));
268  REQUIRE_THROWS_WITH(
269  [&]() {
270  dai::DeviceBootloader bl(deviceInfo, strBadfile);
271  auto currentBlType = bl.getType();
272  }(),
273  ContainsSubstring("doesn't exist"));
274  REQUIRE_THROWS_WITH(
275  [&]() {
276  dai::DeviceBootloader bl(deviceInfo, diaBadfile);
277  auto currentBlType = bl.getType();
278  }(),
279  ContainsSubstring("doesn't exist"));
280 #if defined(_WIN32) && defined(_MSC_VER)
281  REQUIRE_THROWS_WITH(
282  [&]() {
283  dai::DeviceBootloader bl(deviceInfo, &wideBadfile[0]);
284  auto currentBlType = bl.getType();
285  }(),
286  ContainsSubstring("doesn't exist"));
287  REQUIRE_THROWS_WITH(
288  [&]() {
289  dai::DeviceBootloader bl(deviceInfo, wstrBadfile);
290  auto currentBlType = bl.getType();
291  }(),
292  ContainsSubstring("doesn't exist"));
293  REQUIRE_THROWS_WITH(
294  [&]() {
295  dai::DeviceBootloader bl(deviceInfo, diaBadWide);
296  auto currentBlType = bl.getType();
297  }(),
298  ContainsSubstring("doesn't exist"));
299 #endif
300 #if defined(__cpp_lib_filesystem)
301  #if defined(__cpp_lib_char8_t)
302  const auto stdBadpath = std::filesystem::path(PATH4);
303  #else
304  const auto stdBadpath = std::filesystem::u8path(PATH4);
305  #endif
306  REQUIRE_THROWS_WITH(
307  [&]() {
308  dai::DeviceBootloader bl(deviceInfo, stdBadpath);
309  auto currentBlType = bl.getType();
310  }(),
311  ContainsSubstring("doesn't exist"));
312 #endif
313  } else {
314  std::cout << "No devices found" << std::endl;
315  }
316 }
317 
318 TEST_CASE("dai::Path with AssetManager, StereoDepth") {
319  U8CHAR tmp_name4[L_tmpnam];
320  REQUIRE(std::tmpnam(reinterpret_cast<char*>(&tmp_name4[0])) != nullptr);
321  U8STRING string4(tmp_name4);
322  string4 += PATH4;
323  const dai::Path path4(string4);
324  REQUIRE_NOTHROW([&]() {
325  std::ofstream file(path4);
326  file.write(FILETEXT, sizeof(FILETEXT) - 1);
327  }());
328 
329  dai::Pipeline pipeline;
330  CHECK_NOTHROW(pipeline.setCameraTuningBlobPath(string4.c_str()));
331  pipeline.getAssetManager().remove("camTuning");
332  CHECK_NOTHROW(pipeline.setCameraTuningBlobPath(string4));
333  pipeline.getAssetManager().remove("camTuning");
334  CHECK_NOTHROW(pipeline.setCameraTuningBlobPath(path4));
335  pipeline.getAssetManager().remove("camTuning");
336 
337  auto depth = pipeline.create<dai::node::StereoDepth>();
338  CHECK_NOTHROW(depth->loadMeshFiles(string4.c_str(), string4.c_str()));
339  depth->getAssetManager().remove("meshLeft");
340  depth->getAssetManager().remove("meshRight");
341  CHECK_NOTHROW(depth->loadMeshFiles(string4, string4));
342  depth->getAssetManager().remove("meshLeft");
343  depth->getAssetManager().remove("meshRight");
344  CHECK_NOTHROW(depth->loadMeshFiles(path4, path4));
345  depth->getAssetManager().remove("meshLeft");
346  depth->getAssetManager().remove("meshRight");
347 
348 #if defined(_WIN32) && defined(_MSC_VER)
349  const std::wstring widePath4 = path4.native();
350  CHECK_NOTHROW(pipeline.setCameraTuningBlobPath(widePath4.c_str()));
351  pipeline.getAssetManager().remove("camTuning");
352  CHECK_NOTHROW(pipeline.setCameraTuningBlobPath(widePath4));
353  pipeline.getAssetManager().remove("camTuning");
354 
355  CHECK_NOTHROW(depth->loadMeshFiles(widePath4.c_str(), widePath4.c_str()));
356  depth->getAssetManager().remove("meshLeft");
357  depth->getAssetManager().remove("meshRight");
358  CHECK_NOTHROW(depth->loadMeshFiles(widePath4, widePath4));
359  depth->getAssetManager().remove("meshLeft");
360  depth->getAssetManager().remove("meshRight");
361 #endif
362 
363 #if defined(__cpp_lib_filesystem)
364  #if defined(__cpp_lib_char8_t)
365  const auto stdPath4 = std::filesystem::path(string4);
366  #else
367  const auto stdPath4 = std::filesystem::u8path(string4);
368  #endif
369  CHECK_NOTHROW(pipeline.setCameraTuningBlobPath(stdPath4));
370  CHECK_NOTHROW(depth->loadMeshFiles(stdPath4, stdPath4));
371 #endif
372 
373  DELETEFILE(static_cast<NATIVETYPE>(path4).c_str());
374 }
375 
376 TEST_CASE("dai::Path with Script") {
377  U8CHAR tmp_name4[L_tmpnam];
378  REQUIRE(std::tmpnam(reinterpret_cast<char*>(&tmp_name4[0])) != nullptr);
379  U8STRING string4(tmp_name4);
380  string4 += PATH4;
381  const dai::Path path4(string4);
382  REQUIRE_NOTHROW([&]() {
383  std::ofstream file(path4);
384  file.write(FILETEXT, sizeof(FILETEXT) - 1);
385  }());
386 
387  dai::Pipeline pipeline;
388  auto script = pipeline.create<dai::node::Script>();
389 
390  CHECK_NOTHROW(script->setScriptPath(path4));
391  CHECK(script->getScriptPath().u8string() == string4);
392  CHECK(equalStrings(script->getScriptName(), string4));
393  script->getAssetManager().remove("__script");
394 
395  CHECK_NOTHROW(script->setScript("<s>nothing</s>"));
396  CHECK(script->getScriptPath().empty());
397  CHECK(script->getScriptName() == "<script>");
398  script->getAssetManager().remove("__script");
399 
400  CHECK_NOTHROW(script->setScript("<s>nothing</s>", "myname"));
401  CHECK(script->getScriptPath().empty());
402  CHECK(script->getScriptName() == "myname");
403  script->getAssetManager().remove("__script");
404 
405 #if defined(_WIN32) && defined(_MSC_VER)
406  const std::wstring widePath4 = path4.native();
407  CHECK_NOTHROW(script->setScriptPath(widePath4));
408  CHECK(script->getScriptPath().native() == widePath4);
409  CHECK(equalStrings(script->getScriptName(), string4));
410  script->getAssetManager().remove("__script");
411 #endif
412 
413 #if defined(__cpp_lib_filesystem)
414  #if defined(__cpp_lib_char8_t)
415  const auto stdPath4 = std::filesystem::path(string4);
416  #else
417  const auto stdPath4 = std::filesystem::u8path(string4);
418  #endif
419  CHECK_NOTHROW(script->setScriptPath(stdPath4));
420  CHECK(script->getScriptPath().u8string() == stdPath4.u8string());
421  CHECK(equalStrings(script->getScriptName(), string4));
422  script->getAssetManager().remove("__script");
423 #endif
424 
425  DELETEFILE(static_cast<NATIVETYPE>(path4).c_str());
426 }
dai::Path::u8string
std::string u8string() const
Get path in utf-8.
Definition: Path.hpp:164
dai::Pipeline
Represents the pipeline, set of nodes and connections between them.
Definition: Pipeline.hpp:100
PATH5
#define PATH5
Definition: filesystem_test.cpp:40
dai::AssetManager::remove
void remove(const std::string &key)
Definition: AssetManager.cpp:107
dai::node::StereoDepth
StereoDepth node. Compute stereo disparity and depth from left-right image pair.
Definition: StereoDepth.hpp:15
dai::DeviceBootloader
Definition: DeviceBootloader.hpp:29
dai::CalibrationHandler::eepromToJsonFile
bool eepromToJsonFile(dai::Path destPath) const
Definition: CalibrationHandler.cpp:469
dai::DeviceInfo
Definition: XLinkConnection.hpp:27
dai::Pipeline::getAssetManager
const AssetManager & getAssetManager() const
Get pipelines AssetManager as reference.
Definition: Pipeline.hpp:214
u8length
int u8length(const T *str) noexcept
Definition: filesystem_test.cpp:48
dai::node::NeuralNetwork
NeuralNetwork node. Runs a neural inference on input data.
Definition: NeuralNetwork.hpp:18
dai::DeviceBootloader::getType
Type getType() const
Definition: DeviceBootloader.cpp:638
dai::Path::string
std::string string() const
Get path in native-encoding string; no conversion.
Definition: Path.hpp:145
equalStrings
bool equalStrings(const U a, const V b)
Definition: filesystem_test.cpp:55
U8CHAR
#define U8CHAR
Definition: filesystem_test.cpp:32
TEST_CASE
TEST_CASE("dai::Path utf-8 and native char set handling")
Definition: filesystem_test.cpp:61
depthai.hpp
U8STRING
#define U8STRING
Definition: filesystem_test.cpp:33
dai::DeviceBase::readCalibration
CalibrationHandler readCalibration()
Definition: DeviceBase.cpp:1376
NATIVETYPE
#define NATIVETYPE
Definition: filesystem_test.cpp:22
dai::Pipeline::create
std::shared_ptr< N > create()
Definition: Pipeline.hpp:145
dai::node::Script
Definition: Script.hpp:15
MAKENATIVE
#define MAKENATIVE(x)
Definition: filesystem_test.cpp:23
PATH4
#define PATH4
Definition: filesystem_test.cpp:39
PATH1
#define PATH1
Definition: filesystem_test.cpp:36
dai::Path::string_type
std::basic_string< value_type > string_type
Definition: Path.hpp:34
PATH3
#define PATH3
Definition: filesystem_test.cpp:38
FILETEXT
#define FILETEXT
Definition: filesystem_test.cpp:41
dai::CalibrationHandler
Definition: CalibrationHandler.hpp:24
dai::Device
Definition: Device.hpp:21
dai::DeviceBootloader::getFirstAvailableDevice
static std::tuple< bool, DeviceInfo > getFirstAvailableDevice()
Definition: DeviceBootloader.cpp:48
dai::Pipeline::setCameraTuningBlobPath
void setCameraTuningBlobPath(const dai::Path &path)
Set a camera IQ (Image Quality) tuning blob, used for all cameras.
Definition: Pipeline.hpp:257
dai::Path
Represents paths on a filesystem; accepts utf-8, Windows utf-16 wchar_t, or std::filesystem::path.
Definition: Path.hpp:27
NATIVELENGTH
#define NATIVELENGTH(x)
Definition: filesystem_test.cpp:25
dai::Path::native
const string_type & native() const noexcept
Returns native-encoding string by const reference, suitable for use with OS APIs.
Definition: Path.hpp:184
PATH2
#define PATH2
Definition: filesystem_test.cpp:37
DELETEFILE
#define DELETEFILE
Definition: filesystem_test.cpp:24


depthai
Author(s): Martin Peterlin
autogenerated on Sat Mar 22 2025 02:58:19