Skip to content

Commit

Permalink
Move SystemError from eden to edencommon
Browse files Browse the repository at this point in the history
Summary:
To support better telemetry and logging in watchman we want to use Eden's components. Lets migrate and detangle the needed pieces.

This change moves SystemError from eden to edencommon.

Reviewed By: MichaelCuevas

Differential Revision: D54343729

fbshipit-source-id: 7861e3effc9d242fbeda34333078c14c4d021a80
  • Loading branch information
jdelliot authored and facebook-github-bot committed Mar 1, 2024
1 parent 9451e47 commit a6d5a03
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 0 deletions.
45 changes: 45 additions & 0 deletions eden/common/utils/SystemError.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include <system_error>
#include "eden/common/utils/WinError.h"

namespace facebook::eden {

/**
* Return true if this exception contains an errno value in ex.code().value()
*/
inline bool isErrnoError(const std::system_error& ex) {
// std::generic_category is the correct category to represent errno values.
// However folly/Exception.h unfortunately throws errno values as
// std::system_category for now.
return (
ex.code().category() == std::generic_category() ||
ex.code().category() == std::system_category());
}

/**
* Return true if this exception is equivalent to an ENOENT error code.
*/
inline bool isEnoent(const std::system_error& ex) {
auto ret = isErrnoError(ex) && ex.code().value() == ENOENT;
#ifdef _WIN32
ret = ret ||
(ex.code().category() == Win32ErrorCategory::get() &&
(ex.code().value() == ERROR_PATH_NOT_FOUND ||
ex.code().value() == ERROR_FILE_NOT_FOUND));
#endif
return ret;
}

inline bool isEnotempty(const std::system_error& ex) {
return isErrnoError(ex) && ex.code().value() == ENOTEMPTY;
}

} // namespace facebook::eden
170 changes: 170 additions & 0 deletions eden/common/utils/test/SystemErrorTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include <folly/portability/GTest.h>
#include <string>
#include "eden/common/utils/WinError.h"

#ifdef _WIN32

using namespace facebook::eden;

// Test Win32 error
TEST(WinErrorTest, testErrorFileNotFound) {
std::string msg{
"Error ERROR_FILE_NOT_FOUND: Error (0x2) The system cannot find the"
" file specified. "};
auto ex = std::system_error(
ERROR_FILE_NOT_FOUND,
Win32ErrorCategory::get(),
"Error ERROR_FILE_NOT_FOUND");

EXPECT_EQ(msg, ex.what());
}

// Test Win32 success
TEST(WinErrorTest, testErrorSuccess) {
std::string msg{
"Error ERROR_SUCCESS: Error (0x0) The operation completed successfully. "};
auto ex = std::system_error(
ERROR_SUCCESS, Win32ErrorCategory::get(), "Error ERROR_SUCCESS");

EXPECT_EQ(msg, ex.what());
}

// Test HRESULT error
TEST(WinErrorTest, testErrorConfigNotFound) {
std::string msg{
"Error NAP_E_SHV_CONFIG_NOT_FOUND: Error (0x80270012) SHV configuration"
" is not found. "};
auto ex = std::system_error(
NAP_E_SHV_CONFIG_NOT_FOUND,
HResultErrorCategory::get(),
"Error NAP_E_SHV_CONFIG_NOT_FOUND");

EXPECT_EQ(msg, ex.what());
}

// Test HRESULT success
TEST(WinErrorTest, testErrorSOK) {
std::string msg{
"Error S_OK: Error (0x0) The operation completed successfully. "};
auto ex = std::system_error(S_OK, HResultErrorCategory::get(), "Error S_OK");

EXPECT_EQ(msg, ex.what());
}

// Test Invalid error code
TEST(WinErrorTest, testErrorInvalidCode) {
std::string msg{"Error Invalid code: Error (0x22222222) Unknown Error"};
auto ex = std::system_error(
0x22222222, Win32ErrorCategory::get(), "Error Invalid code");

EXPECT_EQ(msg, ex.what());
}

//
// Test exceptionToHResultWrapper, makeHResultError and HResultError exception
//
HRESULT throwHResultError(int arg1, std::string arg2) {
EXPECT_EQ(arg1, 10);
EXPECT_EQ(arg2, "TestString");
throw makeHResultErrorExplicit(E_OUTOFMEMORY, "Test throw");
}

HRESULT catchHResultError(int arg1, std::string arg2) {
return exceptionToHResultWrapper(
[&]() { return throwHResultError(arg1, arg2); });
}

TEST(WinErrorTest, testexceptionToHResultWrapper_E_OUTOFMEMORY) {
int arg1 = 10;
std::string arg2 = "TestString";

EXPECT_EQ(catchHResultError(arg1, arg2), E_OUTOFMEMORY);
}

TEST(WinErrorTest, testexceptionToHResult_E_OUTOFMEMORY) {
try {
throw makeHResultErrorExplicit(E_OUTOFMEMORY, "Test throw");
} catch (const std::exception& ex) {
EXPECT_EQ(exceptionToHResult(ex), E_OUTOFMEMORY);
}
}

TEST(WinErrorTest, testexceptionToHResult_ERROR_ACCESS_DENIED) {
try {
throw makeWin32ErrorExplicit(ERROR_ACCESS_DENIED, "Test throw");
} catch (const std::exception& ex) {
EXPECT_EQ(exceptionToHResult(ex), HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
}
}

//
// Test exceptionToHResult, makeHResultFromWin32Error and HResultError exception
//
HRESULT throwWin32Error(int arg1, std::string arg2) {
EXPECT_EQ(arg1, 2232);
EXPECT_EQ(arg2, "Test String Win32");
throw makeWin32ErrorExplicit(ERROR_FILE_NOT_FOUND, "Test throw");
}

HRESULT catchWin32Error(int arg1, std::string arg2) {
return exceptionToHResultWrapper(
[&]() { return throwWin32Error(arg1, arg2); });
}

TEST(WinErrorTest, testexceptionToHResultWrapper_ERROR_FILE_NOT_FOUND) {
int arg1 = 2232;
std::string arg2 = "Test String Win32";

EXPECT_EQ(
catchWin32Error(arg1, arg2), HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
}

TEST(WinErrorTest, testexceptionToHResult_ERROR_FILE_NOT_FOUND) {
try {
throw makeWin32ErrorExplicit(ERROR_FILE_NOT_FOUND, "Test throw");
} catch (const std::exception& ex) {
EXPECT_EQ(exceptionToHResult(ex), HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
}
}

//
// Test exceptionToHResultWrapper, with system_error and HResultError exception
//
HRESULT throwSystemError(int arg1, std::string arg2) {
EXPECT_EQ(arg1, 1111);
EXPECT_EQ(arg2, "Test String Win32");

throw std::system_error(EEXIST, std::generic_category(), "Test Throw");
}

HRESULT catchSystemError(int arg1, std::string arg2) {
return exceptionToHResultWrapper(
[&]() { return throwSystemError(arg1, arg2); });
}

TEST(WinErrorTest, testexceptionToHResultWrapper_EACCES) {
int arg1 = 1111;
std::string arg2 = "Test String Win32";

EXPECT_EQ(
catchSystemError(arg1, arg2),
HRESULT_FROM_WIN32(ERROR_ERRORS_ENCOUNTERED));
}

TEST(WinErrorTest, testexceptionToHResult_EACCES) {
try {
throw std::system_error(EEXIST, std::generic_category(), "Test Throw");
} catch (const std::exception& ex) {
EXPECT_EQ(
exceptionToHResult(ex), HRESULT_FROM_WIN32(ERROR_ERRORS_ENCOUNTERED));
}
}

#endif

0 comments on commit a6d5a03

Please sign in to comment.