Skip to content
This repository was archived by the owner on Sep 21, 2022. It is now read-only.

Commit 87d96e7

Browse files
Merge pull request #148 from MarkusRannare/filesystem-error-handling
Better handling of filesystem errors
2 parents 07b3053 + 4157f0b commit 87d96e7

File tree

9 files changed

+162
-19
lines changed

9 files changed

+162
-19
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ jobs:
99
strategy:
1010
fail-fast: true
1111
matrix:
12+
action: ['run-tests', 'compile-examples']
1213
name:
1314
# - Ubuntu 16.04 GCC
1415
# - Ubuntu 16.04 Clang
@@ -93,11 +94,16 @@ jobs:
9394
- name: Checkout
9495
uses: actions/checkout@v2
9596

97+
- name: Compile for Tests
98+
id: should-test
99+
if: ${{matrix.action}} == 'run-tests'
100+
run: echo "::set-output name=TEST-FLAGS::-DTEST=on"
101+
96102
- name: Generate project files
97103
run: |
98104
mkdir ${{ matrix.build-dir || '.not-used' }}
99105
cd ${{ matrix.build-dir || '.' }}
100-
cmake ${{ matrix.build-src-dir || '.' }} -Dtest=on ${{ matrix.cmake-args }}
106+
cmake ${{ matrix.build-src-dir || '.' }} ${{ steps.should-test.TEST-FLAGS }} ${{ matrix.cmake-args }}
101107
env:
102108
CC: ${{ matrix.compiler }}
103109
CXX: ${{ matrix.cpp-compiler }}
@@ -111,12 +117,13 @@ jobs:
111117
cmake --build . --config ${{ matrix.build-config || 'Release' }}
112118
113119
- name: Run test cases
120+
if: matrix.action == 'run-tests'
114121
run: |
115122
cd ${{ matrix.build-dir || '.' }}
116123
ctest -C ${{ matrix.build-config || 'Release' }} --output-on-failure
117124
118125
- name: Compile C examples
119-
if: runner.os == 'Linux' || runner.os == 'macOS'
126+
if: ( runner.os == 'Linux' || runner.os == 'macOS' ) && matrix.action == 'compile-examples'
120127
run: |
121128
cd examples/code-samples/c
122129
cmake .
@@ -129,7 +136,7 @@ jobs:
129136
LDFLAGS: ${{ matrix.ldflags || env.LDFLAGS }}
130137

131138
- name: Compile C++ examples
132-
if: runner.os == 'Linux' || runner.os == 'macOS'
139+
if: ( runner.os == 'Linux' || runner.os == 'macOS' ) && matrix.action == 'compile-examples'
133140
run: |
134141
cd examples/code-samples/cpp
135142
cmake .

examples/code-samples/c/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.5)
22
project(examples)
33
include_directories(../../../include)
44
link_directories(../../../build)
5+
enable_language(C)
6+
enable_language(CXX)
57

68
file( GLOB EXAMPLE_SOURCES *.c )
79

examples/code-samples/cpp/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ project(examples)
33
include_directories(../../../include)
44
include_directories(../../../additional_dependencies)
55
set (CMAKE_CXX_STANDARD 11)
6+
enable_language(C)
7+
enable_language(CXX)
68
link_directories(../../../build)
79

810
file( GLOB EXAMPLE_SOURCES *.cpp )

src/Utility.cpp

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,8 @@ std::string getFileExtension(std::string path)
289289
bool isDirectory(const std::string& directory)
290290
{
291291
std::error_code ec;
292-
ghc::filesystem::directory_entry directoryEntry(directory, ec);
293-
if( directoryEntry.exists( ec ) && !ec )
292+
const ghc::filesystem::directory_entry directoryEntry(directory, ec);
293+
if( !ec && directoryEntry.exists( ec ) )
294294
{
295295
return directoryEntry.is_directory( ec ) && !ec;
296296
}
@@ -319,19 +319,54 @@ std::string getDirectoryPath(const std::string &filename)
319319

320320
bool fileExists(const std::string &directory)
321321
{
322-
return ghc::filesystem::is_regular_file(directory);
322+
std::error_code ec;
323+
bool result = ghc::filesystem::exists(directory, ec);
324+
if(ec)
325+
{
326+
writeLogLine("Couldn't check if file '" + directory + "' existes with error code: " + std::to_string(ec.value()) + " and message\n" + ec.message(), MODIO_DEBUGLEVEL_ERROR);
327+
return false;
328+
}
329+
if(result)
330+
{
331+
result = ghc::filesystem::is_regular_file(directory, ec);
332+
if(ec)
333+
{
334+
writeLogLine("Couldn't check if '" + directory + "' is regular file with error code: " + std::to_string(ec.value()) + " and message\n" + ec.message(), MODIO_DEBUGLEVEL_ERROR);
335+
return false;
336+
}
337+
}
338+
return result;
323339
}
324340

325341
std::vector<std::string> getFilenames(const std::string &directory)
326342
{
327343
std::vector<std::string> files;
328344

329-
ghc::filesystem::path directoryPath( directory );
330-
for( auto& p : ghc::filesystem::recursive_directory_iterator(directoryPath) )
345+
const ghc::filesystem::path directoryPath( directory );
346+
if(!ghc::filesystem::exists(directoryPath))
347+
{
348+
writeLogLine("getFilenames: Directory '" + ghc::filesystem::absolute(directory).generic_u8string() + "' doesn't exist!", MODIO_DEBUGLEVEL_ERROR);
349+
return files;
350+
}
351+
352+
const ghc::filesystem::path abosolute = ghc::filesystem::absolute(directory);
353+
354+
// @todo: This might throw. If we get crash reports, we need to convert this to a while loop and pass in a ec to the iterator to handle the exception
355+
// See: https://stackoverflow.com/a/16101173
356+
for( const auto& p : ghc::filesystem::recursive_directory_iterator(directoryPath) )
331357
{
332358
if( !p.is_directory() )
333359
{
334-
files.push_back( ghc::filesystem::relative( p.path(), directoryPath ).generic_u8string() );
360+
std::error_code ec;
361+
ghc::filesystem::path file = ghc::filesystem::relative(p.path(), directoryPath, ec).generic_u8string();
362+
if (!ec)
363+
{
364+
files.push_back(file);
365+
}
366+
else
367+
{
368+
writeLogLine("Couldn't list file '" + directory + "/" + p.path().generic_u8string() + "' with error code: " + std::to_string(ec.value()) + " and message\n" + ec.message(), MODIO_DEBUGLEVEL_ERROR);
369+
}
335370
}
336371
}
337372

@@ -342,12 +377,30 @@ std::vector<std::string> getDirectoryNames(const std::string &root_directory)
342377
{
343378
std::vector<std::string> files;
344379

345-
ghc::filesystem::path rootDirectoryPath(root_directory);
346-
for (auto& p : ghc::filesystem::directory_iterator(rootDirectoryPath))
380+
const ghc::filesystem::path rootDirectoryPath(root_directory);
381+
382+
if(!ghc::filesystem::exists(rootDirectoryPath))
383+
{
384+
writeLogLine("getFilenames: Directory '" + ghc::filesystem::absolute(rootDirectoryPath).generic_u8string() + "' doesn't exist!", MODIO_DEBUGLEVEL_ERROR);
385+
return files;
386+
}
387+
388+
// @todo: This might throw. If we get crash reports, we need to convert this to a while loop and pass in a ec to the iterator to handle the exception
389+
// See: https://stackoverflow.com/a/16101173
390+
for (const auto& p : ghc::filesystem::directory_iterator(rootDirectoryPath))
347391
{
348392
if (p.is_directory())
349393
{
350-
files.push_back(ghc::filesystem::relative(p.path(), rootDirectoryPath).generic_u8string());
394+
std::error_code ec;
395+
ghc::filesystem::path directory = ghc::filesystem::relative(p.path(), rootDirectoryPath, ec).generic_u8string();
396+
if (!ec)
397+
{
398+
files.push_back(directory);
399+
}
400+
else
401+
{
402+
writeLogLine("Couldn't list directory '" + root_directory + "/" + p.path().generic_u8string() + "' with error code: " + std::to_string(ec.value()) + " and message\n" + ec.message(), MODIO_DEBUGLEVEL_ERROR);
403+
}
351404
}
352405
}
353406

src/wrappers/MinizipWrapper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,13 +288,13 @@ void compressFiles(std::string root_directory, std::vector<std::string> filename
288288
password, crcFile, 36, UTF8_FLAG,zip64);
289289

290290
if (err != ZIP_OK)
291-
writeLogLine(std::string("Could not open ") + filenameinzip + " in zipfile, zlib error: " + toString(err), MODIO_DEBUGLEVEL_ERROR);
291+
writeLogLine(std::string("Could not open '") + savefilenameinzip + "' in zipfile, zlib error: " + toString(err), MODIO_DEBUGLEVEL_ERROR);
292292
else
293293
{
294294
fin = modio::platform::fopen(complete_file_path.c_str(), "rb");
295295
if (fin == NULL)
296296
{
297-
writeLogLine(std::string("Could not open ") + filenameinzip + " for reading", MODIO_DEBUGLEVEL_ERROR);
297+
writeLogLine(std::string("Could not open '") + complete_file_path + "' for reading", MODIO_DEBUGLEVEL_ERROR);
298298
}
299299
}
300300

test/Fixture_CleanupFolders.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ void Fixture_CleanupFolders::DeleteTransientDirectories()
1414
for (auto& it : ghc::filesystem::directory_iterator(ghc::filesystem::current_path()))
1515
{
1616
std::vector<ghc::filesystem::path> toDelete;
17-
if (it.is_directory() && !isAllowedDirectory(it.path()))
17+
if (it.is_directory() && !isPersistentDirectory(it.path()))
1818
{
1919
toDelete.push_back(it.path());
2020
}

test/Fixture_CleanupFolders.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Fixture_CleanupFolders : public ::testing::Test
1010
void setFilePermission(std::string fileName, bool access);
1111

1212
// Used for teardown to delete directories that we created
13-
static bool isAllowedDirectory(const ghc::filesystem::path& path)
13+
static bool isPersistentDirectory(const ghc::filesystem::path& path)
1414
{
1515
for (auto& allowedFolder : allowedFolders)
1616
{

test/test_filesystem.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,85 @@ TEST_F(FolderBase, CreateRelativePathSuccess)
174174
createRelativePathTest(u8"unicode/バックソン/");
175175
}
176176

177+
TEST_F(FolderBase, getDirectoryName)
178+
{
179+
// Create testing dataset
180+
ghc::filesystem::create_directory("base_dir");
181+
ghc::filesystem::create_directory("base_dir/subdir_1");
182+
ghc::filesystem::create_directory("base_dir/subdir_2");
183+
ghc::filesystem::create_directory(u8"base_dir/чизкейк");
184+
185+
std::vector<std::string> directories = modio::getDirectoryNames("base_dir");
186+
EXPECT_EQ(directories.size(), 3);
187+
EXPECT_NE(std::find(directories.begin(), directories.end(), "subdir_1"), directories.end());
188+
EXPECT_NE(std::find(directories.begin(), directories.end(), "subdir_2"), directories.end());
189+
const std::string cyrillicFolderName = u8"чизкейк";
190+
EXPECT_NE(std::find(directories.begin(), directories.end(), cyrillicFolderName), directories.end());
191+
}
192+
193+
194+
TEST_F(FolderBase, getDirectoryNameBaseDirUTF8)
195+
{
196+
// Create testing dataset
197+
ghc::filesystem::create_directory(u8"чизкейк");
198+
ghc::filesystem::create_directory(u8"чизкейк/subdir_1");
199+
ghc::filesystem::create_directory(u8"чизкейк/subdir_2");
200+
ghc::filesystem::create_directory(u8"чизкейк/чизкейк");
201+
202+
std::vector<std::string> directories = modio::getDirectoryNames(u8"чизкейк");
203+
EXPECT_EQ(directories.size(), 3);
204+
EXPECT_NE(std::find(directories.begin(), directories.end(), "subdir_1"), directories.end());
205+
EXPECT_NE(std::find(directories.begin(), directories.end(), "subdir_2"), directories.end());
206+
const std::string cyrillicFolderName = u8"чизкейк";
207+
EXPECT_NE(std::find(directories.begin(), directories.end(), cyrillicFolderName), directories.end());
208+
}
209+
210+
TEST_F(FolderBase, getDirectoryNameBadFolder)
211+
{
212+
std::vector<std::string> directories;
213+
EXPECT_NO_THROW( directories = modio::getDirectoryNames("BOGUS"));
214+
EXPECT_EQ(directories.size(), 0);
215+
}
216+
217+
TEST_F(FolderBase, getFilenames)
218+
{
219+
// Create testing dataset
220+
ghc::filesystem::create_directory("base_dir");
221+
std::ofstream("base_dir/file1");
222+
std::ofstream("base_dir/file2");
223+
std::ofstream(u8"base_dir/чизкейк");
224+
225+
std::vector<std::string> files = modio::getFilenames("base_dir");
226+
EXPECT_EQ(files.size(), 3);
227+
EXPECT_NE(std::find(files.begin(), files.end(), "file1"), files.end());
228+
EXPECT_NE(std::find(files.begin(), files.end(), "file2"), files.end());
229+
const std::string cyrillicFileName = u8"чизкейк";
230+
EXPECT_NE(std::find(files.begin(), files.end(), cyrillicFileName), files.end());
231+
}
232+
233+
TEST_F(FolderBase, getFilenamesUTF8)
234+
{
235+
// Create testing dataset
236+
ghc::filesystem::create_directory(u8"чизкейк");
237+
std::ofstream(u8"чизкейк/file1");
238+
std::ofstream(u8"чизкейк/file2");
239+
std::ofstream(u8"чизкейк/чизкейк");
240+
241+
std::vector<std::string> files = modio::getFilenames(u8"чизкейк");
242+
EXPECT_EQ(files.size(), 3);
243+
EXPECT_NE(std::find(files.begin(), files.end(), "file1"), files.end());
244+
EXPECT_NE(std::find(files.begin(), files.end(), "file2"), files.end());
245+
const std::string cyrillicFileName = u8"чизкейк";
246+
EXPECT_NE(std::find(files.begin(), files.end(), cyrillicFileName), files.end());
247+
}
248+
249+
TEST_F(FolderBase, getFilenamesBadFolder)
250+
{
251+
std::vector<std::string> files;
252+
EXPECT_NO_THROW( files = modio::getFilenames("BOGUS"));
253+
EXPECT_EQ(files.size(), 0);
254+
}
255+
177256
static void createRelativePathWithFilename(const std::string& relativePath, const std::string& parentFolder)
178257
{
179258
bool result = modio::createPath(relativePath);

test/test_modio.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ TEST_F(Modio, TestGetMod)
209209
modioShutdown();
210210
}
211211

212-
static std::string downloadedImageFilename = u8"downloaded/logo_original.png";
212+
//static std::string downloadedImageFilename = u8"downloaded/logo_original.png";
213213

214214
u32 calculateCRCOfFile( const std::string& file )
215215
{
@@ -246,7 +246,7 @@ u32 calculateCRCOfFile( const std::string& file )
246246
return crcValue;
247247
}
248248

249-
void onDownloadImage_TestDownloadImage(void* object, ModioResponse response)
249+
/*void onDownloadImage_TestDownloadImage(void* object, ModioResponse response)
250250
{
251251
bool* wait = (bool*)object;
252252
@@ -332,7 +332,7 @@ TEST_F(Modio, TestDownloadImageUnicode)
332332
}
333333
334334
modioShutdown();
335-
}
335+
}*/
336336

337337
TEST_F(Modio, TestInstallMods)
338338
{

0 commit comments

Comments
 (0)