FileIO.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/IO/FileIO.h>
  9. #include <AzCore/IO/Path/Path.h>
  10. #include <AzCore/IO/SystemFile.h>
  11. #include <AzCore/std/string/string.h>
  12. #include <AzCore/PlatformIncl.h>
  13. #include <AzCore/UnitTest/TestTypes.h>
  14. #include <AzCore/Utils/Utils.h>
  15. #include <AzFramework/IO/LocalFileIO.h>
  16. #include <AzFramework/IO/FileOperations.h>
  17. #include <time.h>
  18. #include <AzTest/Utils.h>
  19. #include <AzFrameworkTests_Traits_Platform.h>
  20. #if AZ_TRAIT_USE_WINDOWS_FILE_API
  21. #include <sys/stat.h>
  22. #include <io.h>
  23. #endif
  24. using namespace AZ;
  25. using namespace AZ::IO;
  26. using namespace AZ::Debug;
  27. namespace UnitTest
  28. {
  29. class NameMatchesFilterTest
  30. : public LeakDetectionFixture
  31. {
  32. public:
  33. void run()
  34. {
  35. AZ_TEST_ASSERT(NameMatchesFilter("hello", "hello") == true);
  36. AZ_TEST_ASSERT(NameMatchesFilter("hello", "he?l?") == true);
  37. AZ_TEST_ASSERT(NameMatchesFilter("hello", "he???") == true);
  38. AZ_TEST_ASSERT(NameMatchesFilter("hello", "he*") == true);
  39. AZ_TEST_ASSERT(NameMatchesFilter("hello", "he*o") == true);
  40. AZ_TEST_ASSERT(NameMatchesFilter("hello", "?*?o") == true);
  41. AZ_TEST_ASSERT(NameMatchesFilter("hello", "h?*?") == true);
  42. AZ_TEST_ASSERT(NameMatchesFilter("hello", "h?*?o") == true);
  43. AZ_TEST_ASSERT(NameMatchesFilter("hello", "h?*?o?") == false);
  44. AZ_TEST_ASSERT(NameMatchesFilter("hello", "h***o*") == true);
  45. AZ_TEST_ASSERT(NameMatchesFilter("something", "some??") == false);
  46. AZ_TEST_ASSERT(NameMatchesFilter("hello", "?????*") == true);
  47. AZ_TEST_ASSERT(NameMatchesFilter("hello", "????*") == true);
  48. AZ_TEST_ASSERT(NameMatchesFilter("hello", "h??*") == true);
  49. AZ_TEST_ASSERT(NameMatchesFilter("hello", "??L*") == true);
  50. AZ_TEST_ASSERT(NameMatchesFilter("anything", "**") == true);
  51. AZ_TEST_ASSERT(NameMatchesFilter("any.thing", "*") == true);
  52. AZ_TEST_ASSERT(NameMatchesFilter("anything", "") == false);
  53. AZ_TEST_ASSERT(NameMatchesFilter("system.pak", "*.pak") == true);
  54. AZ_TEST_ASSERT(NameMatchesFilter("system.pakx", "*.pak") == false);
  55. AZ_TEST_ASSERT(NameMatchesFilter("system.pa", "*.pak") == false);
  56. AZ_TEST_ASSERT(NameMatchesFilter("system.pak.3", "*.pak.*") == true);
  57. AZ_TEST_ASSERT(NameMatchesFilter("system.pa.pak", "*.pak") == true);
  58. AZ_TEST_ASSERT(NameMatchesFilter("log1234.log", "log????.log") == true);
  59. AZ_TEST_ASSERT(NameMatchesFilter("log1234.log", "log?????.log") == false);
  60. AZ_TEST_ASSERT(NameMatchesFilter("log151234.log", "log*.log") == true);
  61. AZ_TEST_ASSERT(NameMatchesFilter(".pak", "*.pak") == true);
  62. AZ_TEST_ASSERT(NameMatchesFilter("", "*.pak") == false);
  63. AZ_TEST_ASSERT(NameMatchesFilter("", "") == true);
  64. AZ_TEST_ASSERT(NameMatchesFilter("test.test", "????.????") == true);
  65. AZ_TEST_ASSERT(NameMatchesFilter("testatest", "????.????") == false);
  66. }
  67. };
  68. TEST_F(NameMatchesFilterTest, Test)
  69. {
  70. run();
  71. }
  72. /**
  73. * FileIOStream test
  74. */
  75. class FileIOStreamTest
  76. : public LeakDetectionFixture
  77. {
  78. public:
  79. AZ::IO::LocalFileIO m_fileIO;
  80. AZ::IO::FileIOBase* m_prevFileIO;
  81. FileIOStreamTest()
  82. {
  83. }
  84. void SetUp() override
  85. {
  86. LeakDetectionFixture::SetUp();
  87. m_prevFileIO = AZ::IO::FileIOBase::GetInstance();
  88. AZ::IO::FileIOBase::SetInstance(&m_fileIO);
  89. }
  90. ~FileIOStreamTest() override
  91. {
  92. }
  93. void TearDown() override
  94. {
  95. AZ::IO::FileIOBase::SetInstance(m_prevFileIO);
  96. LeakDetectionFixture::TearDown();
  97. }
  98. void run()
  99. {
  100. AZ::Test::ScopedAutoTempDirectory tempDir;
  101. char fileIOTestPath[AZ::IO::MaxPathLength];
  102. azsnprintf(fileIOTestPath, AZ::IO::MaxPathLength, "%s/fileiotest.txt", tempDir.GetDirectory());
  103. FileIOStream stream(fileIOTestPath, AZ::IO::OpenMode::ModeWrite);
  104. AZ_TEST_ASSERT(stream.IsOpen());
  105. char output[256];
  106. azsnprintf(output, sizeof(output), "magic string");
  107. AZ_TEST_ASSERT(strlen(output) + 1 == stream.Write(strlen(output) + 1, output));
  108. stream.Close();
  109. stream.Open(fileIOTestPath, AZ::IO::OpenMode::ModeRead);
  110. AZ_TEST_ASSERT(stream.IsOpen());
  111. AZ_TEST_ASSERT(strlen(output) + 1 == stream.Read(strlen(output) + 1, output));
  112. AZ_TEST_ASSERT(strcmp(output, "magic string") == 0);
  113. stream.Close();
  114. }
  115. };
  116. TEST_F(FileIOStreamTest, Test)
  117. {
  118. run();
  119. }
  120. namespace LocalFileIOTest
  121. {
  122. class FolderFixture
  123. : public LeakDetectionFixture
  124. {
  125. public:
  126. AZ::Test::ScopedAutoTempDirectory m_tempDir;
  127. AZ::IO::Path m_root;
  128. AZ::IO::Path m_folderName;
  129. AZ::IO::Path m_deepFolder;
  130. AZ::IO::Path m_extraFolder;
  131. AZ::IO::Path m_fileRoot;
  132. AZ::IO::Path m_file01Name;
  133. AZ::IO::Path m_file02Name;
  134. AZ::IO::Path m_file03Name;
  135. int m_randomFolderKey = 0;
  136. FolderFixture()
  137. {
  138. }
  139. void ChooseRandomFolder()
  140. {
  141. m_root = m_tempDir.GetDirectory();
  142. m_folderName = m_root / AZStd::string::format("tmp%08x", m_randomFolderKey);
  143. m_deepFolder = m_folderName / "test" / "subdir";
  144. m_extraFolder = m_deepFolder / "subdir2";
  145. // make a couple files there, and in the root:
  146. m_fileRoot = m_extraFolder;
  147. }
  148. void SetUp() override
  149. {
  150. // lets use a random temp folder name
  151. srand(static_cast<unsigned int>(clock()));
  152. m_randomFolderKey = rand();
  153. LocalFileIO local;
  154. do
  155. {
  156. ChooseRandomFolder();
  157. ++m_randomFolderKey;
  158. } while (local.IsDirectory(m_fileRoot.c_str()));
  159. m_file01Name = m_fileRoot / "file01.txt";
  160. m_file02Name = m_fileRoot / "file02.asdf";
  161. m_file03Name = m_fileRoot / "test123.wha";
  162. }
  163. void TearDown() override
  164. {
  165. }
  166. void CreateTestFiles()
  167. {
  168. constexpr auto openMode = SystemFile::OpenMode::SF_OPEN_WRITE_ONLY
  169. | SystemFile::OpenMode::SF_OPEN_CREATE
  170. | SystemFile::OpenMode::SF_OPEN_CREATE_NEW;
  171. constexpr AZStd::string_view testContent("this is just a test");
  172. LocalFileIO local;
  173. AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
  174. AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
  175. for (const AZ::IO::Path& filename : { m_file01Name, m_file02Name, m_file03Name })
  176. {
  177. SystemFile tempFile;
  178. tempFile.Open(filename.c_str(), openMode);
  179. tempFile.Write(testContent.data(), testContent.size());
  180. tempFile.Close();
  181. }
  182. }
  183. };
  184. class DirectoryTest
  185. : public FolderFixture
  186. {
  187. public:
  188. void run()
  189. {
  190. LocalFileIO local;
  191. AZ_TEST_ASSERT(!local.Exists(m_folderName.c_str()));
  192. AZ::IO::Path longPathCreateTest = m_folderName / "one" / "two" / "three";
  193. AZ_TEST_ASSERT(!local.Exists(longPathCreateTest.c_str()));
  194. AZ_TEST_ASSERT(!local.IsDirectory(longPathCreateTest.c_str()));
  195. AZ_TEST_ASSERT(local.CreatePath(longPathCreateTest.c_str()));
  196. AZ_TEST_ASSERT(local.IsDirectory(longPathCreateTest.c_str()));
  197. AZ_TEST_ASSERT(!local.Exists(m_deepFolder.c_str()));
  198. AZ_TEST_ASSERT(!local.IsDirectory(m_deepFolder.c_str()));
  199. AZ_TEST_ASSERT(local.CreatePath(m_deepFolder.c_str()));
  200. AZ_TEST_ASSERT(local.IsDirectory(m_deepFolder.c_str()));
  201. AZ_TEST_ASSERT(local.Exists(m_deepFolder.c_str()));
  202. AZ_TEST_ASSERT(local.CreatePath(m_deepFolder.c_str()));
  203. AZ_TEST_ASSERT(local.Exists(m_deepFolder.c_str()));
  204. }
  205. };
  206. TEST_F(DirectoryTest, Test)
  207. {
  208. run();
  209. }
  210. class ReadWriteTest
  211. : public FolderFixture
  212. {
  213. public:
  214. void run()
  215. {
  216. LocalFileIO local;
  217. AZ_TEST_ASSERT(!local.Exists(m_fileRoot.c_str()));
  218. AZ_TEST_ASSERT(!local.IsDirectory(m_fileRoot.c_str()));
  219. AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
  220. AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
  221. constexpr auto openMode = SystemFile::OpenMode::SF_OPEN_WRITE_ONLY
  222. | SystemFile::OpenMode::SF_OPEN_CREATE
  223. | SystemFile::OpenMode::SF_OPEN_CREATE_NEW;
  224. SystemFile tempFile;
  225. tempFile.Open(m_file01Name.c_str(), openMode);
  226. constexpr AZStd::string_view testContent("this is just a test");
  227. tempFile.Write(testContent.data(), testContent.size());
  228. tempFile.Close();
  229. AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
  230. AZ_TEST_ASSERT(!local.Open("", AZ::IO::OpenMode::ModeWrite, fileHandle));
  231. AZ_TEST_ASSERT(fileHandle == AZ::IO::InvalidHandle);
  232. // test size without opening:
  233. AZ::u64 fs = 0;
  234. AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), fs));
  235. AZ_TEST_ASSERT(fs == 19);
  236. fileHandle = AZ::IO::InvalidHandle;
  237. AZ::u64 modTimeA = local.ModificationTime(m_file01Name.c_str());
  238. AZ_TEST_ASSERT(modTimeA != 0);
  239. // test invalid handle ops:
  240. AZ_TEST_ASSERT(!local.Seek(fileHandle, 0, AZ::IO::SeekType::SeekFromStart));
  241. AZ_TEST_ASSERT(!local.Close(fileHandle));
  242. AZ_TEST_ASSERT(!local.Eof(fileHandle));
  243. AZ_TEST_ASSERT(!local.Flush(fileHandle));
  244. AZ_TEST_ASSERT(!local.ModificationTime(fileHandle));
  245. AZ_TEST_ASSERT(!local.Read(fileHandle, nullptr, 0, false));
  246. AZ_TEST_ASSERT(!local.Tell(fileHandle, fs));
  247. AZ_TEST_ASSERT(!local.Exists((m_file01Name.Native() + "notexist").c_str()));
  248. AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
  249. AZ_TEST_ASSERT(!local.IsReadOnly(m_file01Name.c_str()));
  250. AZ_TEST_ASSERT(!local.IsDirectory(m_file01Name.c_str()));
  251. // test reads and seeks.
  252. AZ_TEST_ASSERT(local.Open(m_file01Name.c_str(), AZ::IO::OpenMode::ModeRead, fileHandle));
  253. AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
  254. // use this again later...
  255. AZ::u64 modTimeB = local.ModificationTime(fileHandle);
  256. AZ_TEST_ASSERT(modTimeB != 0);
  257. static const size_t testStringLen = 256;
  258. char testString[testStringLen] = { 0 };
  259. // test size on open handle:
  260. fs = 0;
  261. AZ_TEST_ASSERT(local.Size(fileHandle, fs));
  262. AZ_TEST_ASSERT(fs == 19);
  263. // test size without opening, after its already open:
  264. fs = 0;
  265. AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), fs));
  266. AZ_TEST_ASSERT(fs == 19);
  267. AZ::u64 offs = 0;
  268. AZ_TEST_ASSERT(local.Tell(fileHandle, offs));
  269. AZ_TEST_ASSERT(offs == 0);
  270. AZ_TEST_ASSERT(local.Seek(fileHandle, 5, AZ::IO::SeekType::SeekFromStart));
  271. AZ_TEST_ASSERT(!local.Eof(fileHandle));
  272. AZ::u64 actualBytesRead = 0;
  273. // situation
  274. // this is just a test
  275. // ^-------------
  276. // 15 chars
  277. AZ_TEST_ASSERT(local.Tell(fileHandle, offs));
  278. AZ_TEST_ASSERT(offs == 5);
  279. AZ_TEST_ASSERT(!local.Eof(fileHandle));
  280. AZ_TEST_ASSERT(local.Read(fileHandle, testString, testStringLen, false, &actualBytesRead));
  281. AZ_TEST_ASSERT(actualBytesRead == 14);
  282. AZ_TEST_ASSERT(strncmp(testString, "is just a test", 14) == 0);
  283. AZ_TEST_ASSERT(local.Eof(fileHandle));
  284. // this is just a test
  285. // ^
  286. AZ_TEST_ASSERT(local.Seek(fileHandle, -5, AZ::IO::SeekType::SeekFromCurrent));
  287. // this is just a test
  288. // ^----
  289. AZ_TEST_ASSERT(local.Tell(fileHandle, offs));
  290. AZ_TEST_ASSERT(offs == 14);
  291. AZ_TEST_ASSERT(!local.Eof(fileHandle));
  292. AZ_TEST_ASSERT(local.Read(fileHandle, testString, testStringLen, false, &actualBytesRead));
  293. AZ_TEST_ASSERT(actualBytesRead == 5);
  294. AZ_TEST_ASSERT(strncmp(testString, " test", 5) == 0);
  295. AZ_TEST_ASSERT(local.Eof(fileHandle));
  296. // this is just a test
  297. // ^
  298. AZ_TEST_ASSERT(local.Seek(fileHandle, -6, AZ::IO::SeekType::SeekFromEnd));
  299. // this is just a test
  300. // ^---
  301. AZ_TEST_ASSERT(local.Tell(fileHandle, offs));
  302. AZ_TEST_ASSERT(offs == 13);
  303. AZ_TEST_ASSERT(!local.Eof(fileHandle));
  304. AZ_TEST_ASSERT(local.Read(fileHandle, testString, 4, true, &actualBytesRead));
  305. AZ_TEST_ASSERT(actualBytesRead == 4);
  306. AZ_TEST_ASSERT(strncmp(testString, "a te", 4) == 0);
  307. AZ_TEST_ASSERT(local.Tell(fileHandle, offs));
  308. AZ_TEST_ASSERT(offs == 17);
  309. AZ_TEST_ASSERT(!local.Eof(fileHandle));
  310. // fail when not enough bytes:
  311. AZ_TEST_ASSERT(!local.Read(fileHandle, testString, testStringLen, true, &actualBytesRead));
  312. AZ_TEST_ASSERT(local.Eof(fileHandle));
  313. AZ_TEST_ASSERT(local.Close(fileHandle));
  314. fileHandle = AZ::IO::InvalidHandle;
  315. }
  316. };
  317. TEST_F(ReadWriteTest, Test)
  318. {
  319. run();
  320. }
  321. class PermissionsTest
  322. : public FolderFixture
  323. {
  324. public:
  325. void run()
  326. {
  327. LocalFileIO local;
  328. CreateTestFiles();
  329. #if AZ_TRAIT_AZFRAMEWORKTEST_PERFORM_CHMOD_TEST
  330. #if AZ_TRAIT_USE_WINDOWS_FILE_API
  331. _chmod(m_file01Name.c_str(), _S_IREAD);
  332. #else
  333. chmod(m_file01Name.c_str(), S_IRUSR | S_IRGRP | S_IROTH);
  334. #endif
  335. AZ_TEST_ASSERT(local.IsReadOnly(m_file01Name.c_str()));
  336. #if AZ_TRAIT_USE_WINDOWS_FILE_API
  337. _chmod(m_file01Name.c_str(), _S_IREAD | _S_IWRITE);
  338. #else
  339. chmod(m_file01Name.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  340. #endif
  341. #endif
  342. AZ_TEST_ASSERT(!local.IsReadOnly(m_file01Name.c_str()));
  343. }
  344. };
  345. TEST_F(PermissionsTest, Test)
  346. {
  347. run();
  348. }
  349. class CopyMoveTests
  350. : public FolderFixture
  351. {
  352. public:
  353. void run()
  354. {
  355. LocalFileIO local;
  356. AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
  357. AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
  358. {
  359. #ifdef AZ_COMPILER_MSVC
  360. FILE* tempFile;
  361. fopen_s(&tempFile, m_file01Name.c_str(), "wb");
  362. #else
  363. FILE* tempFile = fopen(m_file01Name.c_str(), "wb");
  364. #endif
  365. fwrite("this is just a test", 1, 19, tempFile);
  366. fclose(tempFile);
  367. }
  368. // make sure attributes are copied, such as original modtime:
  369. AZStd::this_thread::sleep_for(AZStd::chrono::seconds(1));
  370. AZ_TEST_ASSERT(local.Copy(m_file01Name.c_str(), m_file02Name.c_str()));
  371. AZ_TEST_ASSERT(local.Copy(m_file01Name.c_str(), m_file03Name.c_str()));
  372. AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
  373. AZ_TEST_ASSERT(local.Exists(m_file02Name.c_str()));
  374. AZ_TEST_ASSERT(local.Exists(m_file03Name.c_str()));
  375. AZ_TEST_ASSERT(!local.DestroyPath(m_file01Name.c_str())); // you may not destroy files.
  376. AZ_TEST_ASSERT(!local.DestroyPath(m_file02Name.c_str()));
  377. AZ_TEST_ASSERT(!local.DestroyPath(m_file03Name.c_str()));
  378. AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
  379. AZ_TEST_ASSERT(local.Exists(m_file02Name.c_str()));
  380. AZ_TEST_ASSERT(local.Exists(m_file03Name.c_str()));
  381. AZ::u64 f1s = 0;
  382. AZ::u64 f2s = 0;
  383. AZ::u64 f3s = 0;
  384. AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), f1s));
  385. AZ_TEST_ASSERT(local.Size(m_file02Name.c_str(), f2s));
  386. AZ_TEST_ASSERT(local.Size(m_file03Name.c_str(), f3s));
  387. AZ_TEST_ASSERT(f1s == f2s);
  388. AZ_TEST_ASSERT(f1s == f3s);
  389. // Copying over top other files is allowed
  390. SystemFile file;
  391. EXPECT_TRUE(file.Open(m_file01Name.c_str(), SystemFile::SF_OPEN_WRITE_ONLY));
  392. file.Write("this is just a test that is longer", 34);
  393. file.Close();
  394. EXPECT_TRUE(local.Copy(m_file01Name.c_str(), m_file02Name.c_str()));
  395. f1s = 0;
  396. f2s = 0;
  397. f3s = 0;
  398. EXPECT_TRUE(local.Size(m_file01Name.c_str(), f1s));
  399. EXPECT_TRUE(local.Size(m_file02Name.c_str(), f2s));
  400. EXPECT_TRUE(local.Size(m_file03Name.c_str(), f3s));
  401. EXPECT_EQ(f1s, f2s);
  402. EXPECT_NE(f1s, f3s);
  403. }
  404. };
  405. TEST_F(CopyMoveTests, Test)
  406. {
  407. run();
  408. }
  409. class ModTimeTest
  410. : public FolderFixture
  411. {
  412. public:
  413. void run()
  414. {
  415. AZ::IO::LocalFileIO local;
  416. CreateTestFiles();
  417. AZ::u64 modTimeC = 0;
  418. AZ::u64 modTimeD = 0;
  419. modTimeC = local.ModificationTime(m_file02Name.c_str());
  420. modTimeD = local.ModificationTime(m_file03Name.c_str());
  421. // make sure modtimes are in ascending order (at least)
  422. AZ_TEST_ASSERT(modTimeD >= modTimeC);
  423. // now touch some of the files. This is also how we test append mode, and write mode.
  424. AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
  425. AZ_TEST_ASSERT(local.Open(m_file02Name.c_str(), AZ::IO::OpenMode::ModeAppend | AZ::IO::OpenMode::ModeBinary, fileHandle));
  426. AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
  427. AZ_TEST_ASSERT(local.Write(fileHandle, "more", 4));
  428. AZ_TEST_ASSERT(local.Close(fileHandle));
  429. // No-append-mode
  430. AZ_TEST_ASSERT(local.Open(m_file03Name.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary, fileHandle));
  431. AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
  432. AZ_TEST_ASSERT(local.Write(fileHandle, "more", 4));
  433. AZ_TEST_ASSERT(local.Close(fileHandle));
  434. modTimeC = local.ModificationTime(m_file02Name.c_str());
  435. modTimeD = local.ModificationTime(m_file03Name.c_str());
  436. AZ_TEST_ASSERT(modTimeD >= modTimeC); // should never be descending
  437. AZ::u64 f1s = 0;
  438. AZ::u64 f2s = 0;
  439. AZ::u64 f3s = 0;
  440. AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), f1s));
  441. AZ_TEST_ASSERT(local.Size(m_file02Name.c_str(), f2s));
  442. AZ_TEST_ASSERT(local.Size(m_file03Name.c_str(), f3s));
  443. AZ_TEST_ASSERT(f2s == f1s + 4);
  444. AZ_TEST_ASSERT(f3s == 4);
  445. }
  446. };
  447. TEST_F(ModTimeTest, Test)
  448. {
  449. run();
  450. }
  451. class FindFilesTest
  452. : public FolderFixture
  453. {
  454. public:
  455. void run()
  456. {
  457. AZ::IO::LocalFileIO local;
  458. CreateTestFiles();
  459. AZStd::vector<AZ::IO::Path> resultFiles;
  460. bool foundOK = local.FindFiles(m_fileRoot.c_str(), "*",
  461. [&](const char* filePath) -> bool
  462. {
  463. resultFiles.push_back(filePath);
  464. return false; // early out!
  465. });
  466. AZ_TEST_ASSERT(foundOK);
  467. AZ_TEST_ASSERT(resultFiles.size() == 1);
  468. resultFiles.clear();
  469. foundOK = local.FindFiles(m_fileRoot.c_str(), "*",
  470. [&](const char* filePath) -> bool
  471. {
  472. resultFiles.push_back(filePath);
  473. return true; // continue iterating
  474. });
  475. AZ_TEST_ASSERT(foundOK);
  476. AZ_TEST_ASSERT(resultFiles.size() == 3);
  477. // note: following tests accumulate more files without clearing resultfiles.
  478. foundOK = local.FindFiles(m_fileRoot.c_str(), "*.txt",
  479. [&](const char* filePath) -> bool
  480. {
  481. resultFiles.push_back(filePath);
  482. return true; // continue iterating
  483. });
  484. AZ_TEST_ASSERT(foundOK);
  485. AZ_TEST_ASSERT(resultFiles.size() == 4);
  486. foundOK = local.FindFiles(m_fileRoot.c_str(), "file*.asdf",
  487. [&](const char* filePath) -> bool
  488. {
  489. resultFiles.push_back(filePath);
  490. return true; // continue iterating
  491. });
  492. AZ_TEST_ASSERT(foundOK);
  493. AZ_TEST_ASSERT(resultFiles.size() == 5);
  494. foundOK = local.FindFiles(m_fileRoot.c_str(), "asaf.asdf",
  495. [&](const char* filePath) -> bool
  496. {
  497. resultFiles.push_back(filePath);
  498. return true; // continue iterating
  499. });
  500. AZ_TEST_ASSERT(foundOK);
  501. AZ_TEST_ASSERT(resultFiles.size() == 5);
  502. resultFiles.clear();
  503. // test to make sure directories show up:
  504. foundOK = local.FindFiles(m_deepFolder.c_str(), "*",
  505. [&](const char* filePath) -> bool
  506. {
  507. resultFiles.push_back(filePath);
  508. return true; // continue iterating
  509. });
  510. // canonicalize the name in the same way that find does.
  511. //AZStd::replace() m_extraFolder.replace('\\', '/'); FIXME PPATEL
  512. AZ_TEST_ASSERT(foundOK);
  513. AZ_TEST_ASSERT(resultFiles.size() == 1);
  514. AZ_TEST_ASSERT(resultFiles[0] == m_extraFolder);
  515. resultFiles.clear();
  516. foundOK = local.FindFiles("o:137787621!@#$%^&&**())_+[])_", "asaf.asdf",
  517. [&](const char* filePath) -> bool
  518. {
  519. resultFiles.push_back(filePath);
  520. return true; // continue iterating
  521. });
  522. AZ_TEST_ASSERT(!foundOK);
  523. AZ_TEST_ASSERT(resultFiles.size() == 0);
  524. AZ::IO::Path file04Name = m_fileRoot / "test.wha";
  525. // test rename
  526. AZ_TEST_ASSERT(local.Rename(m_file03Name.c_str(), file04Name.c_str()));
  527. AZ_TEST_ASSERT(!local.Rename(m_file03Name.c_str(), file04Name.c_str()));
  528. AZ_TEST_ASSERT(local.Rename(file04Name.c_str(), file04Name.c_str())); // this is valid and ok
  529. AZ_TEST_ASSERT(local.Exists(file04Name.c_str()));
  530. AZ_TEST_ASSERT(!local.Exists(m_file03Name.c_str()));
  531. AZ_TEST_ASSERT(!local.IsDirectory(file04Name.c_str()));
  532. AZ::u64 f3s = 0;
  533. AZ_TEST_ASSERT(local.Size(file04Name.c_str(), f3s));
  534. AZ_TEST_ASSERT(f3s == 19);
  535. // deep destroy directory:
  536. AZ_TEST_ASSERT(local.DestroyPath(m_folderName.c_str()));
  537. AZ_TEST_ASSERT(!local.Exists(m_folderName.c_str()));
  538. }
  539. };
  540. TEST_F(FindFilesTest, Test)
  541. {
  542. run();
  543. }
  544. using AliasTest = FolderFixture;
  545. TEST_F(AliasTest, Test)
  546. {
  547. AZ::IO::LocalFileIO local;
  548. // test aliases
  549. local.SetAlias("@test@", m_folderName.c_str());
  550. const char* testDest1 = local.GetAlias("@test@");
  551. AZ_TEST_ASSERT(testDest1 != nullptr);
  552. const char* testDest2 = local.GetAlias("@NOPE@");
  553. AZ_TEST_ASSERT(testDest2 == nullptr);
  554. testDest1 = local.GetAlias("@test@"); // try with different case
  555. AZ_TEST_ASSERT(testDest1 != nullptr);
  556. // test resolving
  557. const char* aliasTestPath = "@test@\\some\\path\\somefile.txt";
  558. char aliasResolvedPath[AZ::IO::MaxPathLength];
  559. bool resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, AZ::IO::MaxPathLength);
  560. AZ_TEST_ASSERT(resolveDidWork);
  561. AZ::IO::Path expectedResolvedPath = m_folderName / "some/path/somefile.txt";
  562. AZ_TEST_ASSERT(aliasResolvedPath == expectedResolvedPath);
  563. // more resolve path tests with invalid inputs
  564. const char* testPath = nullptr;
  565. char* testResolvedPath = nullptr;
  566. resolveDidWork = local.ResolvePath(testPath, aliasResolvedPath, AZ::IO::MaxPathLength);
  567. AZ_TEST_ASSERT(!resolveDidWork);
  568. resolveDidWork = local.ResolvePath(aliasTestPath, testResolvedPath, AZ::IO::MaxPathLength);
  569. AZ_TEST_ASSERT(!resolveDidWork);
  570. resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, 0);
  571. AZ_TEST_ASSERT(!resolveDidWork);
  572. // Test that sending in a too small output path fails,
  573. // if the output buffer is smaller than the string being resolved
  574. size_t SMALLER_THAN_PATH_BEING_RESOLVED = strlen(aliasTestPath) - 1;
  575. AZ_TEST_START_TRACE_SUPPRESSION;
  576. resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, SMALLER_THAN_PATH_BEING_RESOLVED);
  577. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  578. AZ_TEST_ASSERT(!resolveDidWork);
  579. // Test that sending in a too small output path fails,
  580. // if the output buffer is too small to hold the resolved path
  581. size_t SMALLER_THAN_FINAL_RESOLVED_PATH = expectedResolvedPath.Native().length() - 1;
  582. AZ_TEST_START_TRACE_SUPPRESSION;
  583. resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, SMALLER_THAN_FINAL_RESOLVED_PATH);
  584. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  585. AZ_TEST_ASSERT(!resolveDidWork);
  586. // test clearing an alias
  587. local.ClearAlias("@test@");
  588. testDest1 = local.GetAlias("@test@");
  589. AZ_TEST_ASSERT(testDest1 == nullptr);;
  590. }
  591. TEST_F(AliasTest, ResolvePath_PathViewOverload_Succeeds)
  592. {
  593. AZ::IO::LocalFileIO local;
  594. local.SetAlias("@test@", m_folderName.c_str());
  595. AZ::IO::PathView aliasTestPath = "@test@\\some\\path\\somefile.txt";
  596. AZ::IO::FixedMaxPath aliasResolvedPath;
  597. ASSERT_TRUE(local.ResolvePath(aliasResolvedPath, aliasTestPath));
  598. AZ::IO::Path expectedResolvedPath = m_folderName / "some" / "path" / "somefile.txt";
  599. EXPECT_EQ(expectedResolvedPath, aliasResolvedPath);
  600. AZStd::optional<AZ::IO::FixedMaxPath> optionalResolvedPath = local.ResolvePath(aliasTestPath);
  601. ASSERT_TRUE(optionalResolvedPath);
  602. EXPECT_EQ(expectedResolvedPath, optionalResolvedPath.value());
  603. }
  604. TEST_F(AliasTest, ResolvePath_PathViewOverloadWithEmptyPath_Fails)
  605. {
  606. AZ::IO::LocalFileIO local;
  607. local.SetAlias("@test@", m_folderName.c_str());
  608. AZ::IO::FixedMaxPath aliasResolvedPath;
  609. EXPECT_FALSE(local.ResolvePath(aliasResolvedPath, {}));
  610. }
  611. TEST_F(AliasTest, ConvertToAlias_PathViewOverloadContainingExactAliasPath_Succeeds)
  612. {
  613. AZ::IO::LocalFileIO local;
  614. AZ::IO::FixedMaxPathString aliasFolder;
  615. EXPECT_TRUE(local.ConvertToAbsolutePath("/temp", aliasFolder.data(), aliasFolder.capacity()));
  616. aliasFolder.resize_no_construct(AZStd::char_traits<char>::length(aliasFolder.data()));
  617. local.SetAlias("@test@", aliasFolder.c_str());
  618. AZ::IO::FixedMaxPath aliasPath;
  619. ASSERT_TRUE(local.ConvertToAlias(aliasPath, AZ::IO::PathView(aliasFolder)));
  620. EXPECT_STREQ("@test@", aliasPath.c_str());
  621. AZStd::optional<AZ::IO::FixedMaxPath> optionalAliasPath = local.ConvertToAlias(AZ::IO::PathView(aliasFolder));
  622. ASSERT_TRUE(optionalAliasPath);
  623. EXPECT_STREQ("@test@", optionalAliasPath->c_str());
  624. }
  625. TEST_F(AliasTest, ConvertToAlias_PathViewOverloadStartingWithAliasPath_Succeeds)
  626. {
  627. AZ::IO::LocalFileIO local;
  628. AZ::IO::FixedMaxPathString aliasFolder;
  629. EXPECT_TRUE(local.ConvertToAbsolutePath("/temp", aliasFolder.data(), aliasFolder.capacity()));
  630. aliasFolder.resize_no_construct(AZStd::char_traits<char>::length(aliasFolder.data()));
  631. local.SetAlias("@test@", aliasFolder.c_str());
  632. const auto testPath = AZ::IO::FixedMaxPathString::format("%s/Dir", aliasFolder.c_str());
  633. AZ::IO::FixedMaxPath aliasPath;
  634. ASSERT_TRUE(local.ConvertToAlias(aliasPath, AZ::IO::PathView(testPath)));
  635. EXPECT_STREQ("@test@/Dir", aliasPath.c_str());
  636. }
  637. TEST_F(AliasTest, ConvertToAlias_PathViewOverloadInputPathWithoutPathSeparatorAndStartWithAliasPath_DoesNotSubstituteAlias)
  638. {
  639. AZ::IO::LocalFileIO local;
  640. AZ::IO::FixedMaxPathString aliasFolder;
  641. EXPECT_TRUE(local.ConvertToAbsolutePath("/temp", aliasFolder.data(), aliasFolder.capacity()));
  642. aliasFolder.resize_no_construct(AZStd::char_traits<char>::length(aliasFolder.data()));
  643. local.SetAlias("@test@", aliasFolder.c_str());
  644. // Because there is no trailing path separator, the input path is really "/tempDir"
  645. // Therefore the "/temp" alias shouldn't match as an alias should match a full directory
  646. const auto testPath = AZ::IO::FixedMaxPathString::format("%sDir", aliasFolder.c_str());
  647. AZ::IO::FixedMaxPath aliasPath{ testPath };
  648. EXPECT_TRUE(local.ConvertToAlias(aliasPath, AZ::IO::PathView(testPath)));
  649. EXPECT_STREQ(testPath.c_str(), aliasPath.c_str());
  650. }
  651. TEST_F(AliasTest, ConvertToAlias_PathViewOverloadWithTooLongPath_ReturnsFalse)
  652. {
  653. AZ::IO::LocalFileIO local;
  654. AZ::IO::FixedMaxPathString aliasFolder;
  655. EXPECT_TRUE(local.ConvertToAbsolutePath("/temp", aliasFolder.data(), aliasFolder.capacity()));
  656. aliasFolder.resize_no_construct(AZStd::char_traits<char>::length(aliasFolder.data()));
  657. local.SetAlias("@LongAliasThatIsLong@", aliasFolder.c_str());
  658. AZStd::string path = static_cast<AZStd::string_view>(aliasFolder);
  659. path.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR);
  660. // The length of "@alias@" is longer than the aliased path
  661. // Therefore ConvertToAlias should fail due to not being able to fit the alias in the buffer
  662. path.append(AZ::IO::MaxPathLength, 'a');
  663. AZ::IO::FixedMaxPath aliasPath;
  664. AZ_TEST_START_TRACE_SUPPRESSION;
  665. EXPECT_FALSE(local.ConvertToAlias(aliasPath, AZ::IO::PathView(path)));
  666. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  667. }
  668. TEST_F(AliasTest, ReplaceAlias_CanReplaceAliasInplace_Succeeds)
  669. {
  670. AZ::IO::LocalFileIO local;
  671. AZ::IO::FixedMaxPathString aliasFolder;
  672. auto CreateTestAbsPath = [&local](char* ptr, size_t size) -> size_t
  673. {
  674. // If the path was successfully converted to an absolute path
  675. // then take the string length of it to figure out where to resize
  676. // the fixed_string downwards
  677. return local.ConvertToAbsolutePath("/temp", ptr, size) ?
  678. AZStd::char_traits<char>::length(ptr) : 0;
  679. };
  680. aliasFolder.resize_and_overwrite(aliasFolder.max_size(), CreateTestAbsPath);
  681. local.SetAlias("@test@", aliasFolder.c_str());
  682. // First replace the alias into a new FixedMaxPath
  683. const AZ::IO::FixedMaxPath testValue = "@test@/Assets/Materials/Types/MaterialInputs/BaseColorPropertyGroup.json";
  684. AZ::IO::FixedMaxPath expectedResolvedValue;
  685. EXPECT_TRUE(local.ReplaceAlias(expectedResolvedValue, testValue));
  686. // Make a copy of the testValue into a FixedMaxPath and resolve it inplace
  687. AZ::IO::FixedMaxPath testPath = testValue;
  688. EXPECT_TRUE(local.ReplaceAlias(testPath, testPath));
  689. EXPECT_EQ(expectedResolvedValue, testPath);
  690. }
  691. TEST_F(AliasTest, GetAlias_LogsError_WhenAccessingDeprecatedAlias_Succeeds)
  692. {
  693. AZ::IO::LocalFileIO local;
  694. AZ::IO::FixedMaxPathString aliasFolder;
  695. EXPECT_TRUE(local.ConvertToAbsolutePath("/temp", aliasFolder.data(), aliasFolder.capacity()));
  696. aliasFolder.resize_no_construct(AZStd::char_traits<char>::length(aliasFolder.data()));
  697. local.SetAlias("@test@", aliasFolder.c_str());
  698. local.SetDeprecatedAlias("@deprecated@", "@test@");
  699. local.SetDeprecatedAlias("@deprecatednonexistent@", "@nonexistent@");
  700. local.SetDeprecatedAlias("@deprecatedsecond@", "@deprecated@");
  701. local.SetDeprecatedAlias("@deprecatednonaliaspath@", aliasFolder);
  702. AZ_TEST_START_TRACE_SUPPRESSION;
  703. const char* testAlias = local.GetAlias("@test@");
  704. ASSERT_NE(nullptr, testAlias);
  705. EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias));
  706. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  707. // Validate that accessing Deprecated Alias results in AZ_Error
  708. AZ_TEST_START_TRACE_SUPPRESSION;
  709. testAlias = local.GetAlias("@deprecated@");
  710. ASSERT_NE(nullptr, testAlias);
  711. EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias));
  712. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  713. AZ_TEST_START_TRACE_SUPPRESSION;
  714. testAlias = local.GetAlias("@deprecatednonexistent@");
  715. EXPECT_EQ(nullptr, testAlias);
  716. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  717. AZ_TEST_START_TRACE_SUPPRESSION;
  718. testAlias = local.GetAlias("@deprecatedsecond@");
  719. ASSERT_NE(nullptr, testAlias);
  720. EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias));
  721. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  722. AZ_TEST_START_TRACE_SUPPRESSION;
  723. testAlias = local.GetAlias("@deprecatednonaliaspath@");
  724. ASSERT_NE(nullptr, testAlias);
  725. EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias));
  726. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  727. }
  728. class SmartMoveTests
  729. : public FolderFixture
  730. {
  731. public:
  732. void run()
  733. {
  734. LocalFileIO localFileIO;
  735. AZ::IO::FileIOBase::SetInstance(&localFileIO);
  736. AZ::IO::Path path = m_file01Name.ParentPath();
  737. AZ_TEST_ASSERT(localFileIO.CreatePath(path.c_str()));
  738. path = m_file01Name.ParentPath();
  739. AZ_TEST_ASSERT(localFileIO.CreatePath(path.c_str()));
  740. AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
  741. localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
  742. localFileIO.Write(fileHandle, "DummyFile", 9);
  743. localFileIO.Close(fileHandle);
  744. AZ::IO::HandleType fileHandle1 = AZ::IO::InvalidHandle;
  745. localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle1);
  746. localFileIO.Write(fileHandle1, "TestFile", 8);
  747. localFileIO.Close(fileHandle1);
  748. fileHandle1 = AZ::IO::InvalidHandle;
  749. localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
  750. static const size_t testStringLen = 256;
  751. char testString[testStringLen] = { 0 };
  752. localFileIO.Read(fileHandle1, testString, testStringLen);
  753. localFileIO.Close(fileHandle1);
  754. AZ_TEST_ASSERT(strncmp(testString, "TestFile", 8) == 0);
  755. // try swapping files when none of the files are in use
  756. AZ_TEST_ASSERT(AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
  757. fileHandle1 = AZ::IO::InvalidHandle;
  758. localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
  759. testString[0] = '\0';
  760. localFileIO.Read(fileHandle1, testString, testStringLen);
  761. localFileIO.Close(fileHandle1);
  762. AZ_TEST_ASSERT(strncmp(testString, "DummyFile", 9) == 0);
  763. //try swapping files when source file is not present, this should fail
  764. AZ_TEST_ASSERT(!AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
  765. fileHandle = AZ::IO::InvalidHandle;
  766. localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
  767. localFileIO.Write(fileHandle, "TestFile", 8);
  768. localFileIO.Close(fileHandle);
  769. #if AZ_TRAIT_AZFRAMEWORKTEST_MOVE_WHILE_OPEN
  770. fileHandle1 = AZ::IO::InvalidHandle;
  771. localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
  772. testString[0] = '\0';
  773. localFileIO.Read(fileHandle1, testString, testStringLen);
  774. // try swapping files when the destination file is open for read only,
  775. // since window is unable to move files that are open for read, this will fail.
  776. AZ_TEST_ASSERT(!AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
  777. localFileIO.Close(fileHandle1);
  778. #endif
  779. fileHandle = AZ::IO::InvalidHandle;
  780. localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle);
  781. // try swapping files when the source file is open for read only
  782. AZ_TEST_ASSERT(AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
  783. localFileIO.Close(fileHandle);
  784. fileHandle1 = AZ::IO::InvalidHandle;
  785. localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
  786. testString[0] = '\0';
  787. localFileIO.Read(fileHandle1, testString, testStringLen);
  788. AZ_TEST_ASSERT(strncmp(testString, "TestFile", 8) == 0);
  789. localFileIO.Close(fileHandle1);
  790. localFileIO.Remove(m_file01Name.c_str());
  791. localFileIO.Remove(m_file02Name.c_str());
  792. localFileIO.DestroyPath(m_root.c_str());
  793. AZ::IO::FileIOBase::SetInstance(nullptr);
  794. }
  795. };
  796. TEST_F(SmartMoveTests, Test)
  797. {
  798. run();
  799. }
  800. }
  801. } // namespace UnitTest