fix: add testbench for new added code. fix issues.

- add testbench for new added code in StdPatch.
- add documentation for new added code.
- fix the old usage of StdPatch::ToStdPath in ExceptionHelper.
This commit is contained in:
yyc12345 2024-08-15 10:38:58 +08:00
parent 59c185a424
commit f3a88e951c
5 changed files with 78 additions and 17 deletions

View File

@ -3,6 +3,41 @@ namespace YYCC::StdPatch {
\page std_patch Standard Library Patch \page std_patch Standard Library Patch
\section std_patch__starts_with_ends_with Starts With & Ends With
\c std::basic_string::starts_with and \c std::basic_string::ends_with (also available in \c std::basic_string_view)
are functions introduced in C++ 20 and unavailable in C++ 17.
YYCC::StdPatch provides a patch for these function in C++ 17 environment.
Please note these implementations are following implementation instruction presented by CppReference website.
And it should have the same performance with vanilla functions because Microsoft STL use the same way to implement.
These implementations will not fallback to vanilla function even they are available.
Because their performance are good.
To use these functions, you just need to call them like corresponding vanilla functions.
Our implementations provide all necessary overloads.
The only thing you need to do is provide the string self as the first argument,
because our implementations can not be inserted as a class member of string.
There is an example:
\code
YYCC::StdPatch::StartsWith(YYCC_U8("aabbcc"), YYCC_U8("aa"));
YYCC::StdPatch::EndsWith(YYCC_U8("aabbcc"), YYCC_U8("cc"));
\endcode
\section std_patch__contains Contains
\c Contains function in standard library ordered and unordered successive container are also introduced in C++ 20.
YYCC::StdPatch provides a patch for this function in C++ 17 environment.
Please note this implementation will fallback to vanilla function if it is available.
Because our implementation is a remedy (there is no way to use public class member to have the same performance of vanilla function).
There is an example about how to use it:
\code
std::set<int> test { 1, 5 };
YYCC::StdPatch::Contains(test, static_cast<int>(5));
\endcode
\section std_patch__fs_path std::filesystem::path Patch \section std_patch__fs_path std::filesystem::path Patch
As you know, the underlying char type of \c std::filesystem::path is \c wchar_t on Windows, As you know, the underlying char type of \c std::filesystem::path is \c wchar_t on Windows,

View File

@ -15,6 +15,9 @@ Currently this namespace has following functions:
\li #GetModuleFileName: Get the path to module in file system by given handle. \li #GetModuleFileName: Get the path to module in file system by given handle.
\li #GetLocalAppData: Get the path inside \%LOCALAPPDATA\% \li #GetLocalAppData: Get the path inside \%LOCALAPPDATA\%
\li #IsValidCodePage: Check whether given code page number is valid. \li #IsValidCodePage: Check whether given code page number is valid.
\li #CopyFile: The UTF8 version of Win32 \c CopyFile.
\li #MoveFile: The UTF8 version of Win32 \c MoveFile.
\li #DeleteFile: The UTF8 version of Win32 \c DeleteFile.
*/ */
} }

View File

@ -459,7 +459,7 @@ namespace YYCC::ExceptionHelper {
if (!YYCC::WinFctHelper::GetModuleFileName(NULL, u8_process_path)) if (!YYCC::WinFctHelper::GetModuleFileName(NULL, u8_process_path))
return false; return false;
// extract file name from full path by std::filesystem::path // extract file name from full path by std::filesystem::path
std::filesystem::path process_path(StdPatch::ToStdPath(u8_process_path.c_str())); std::filesystem::path process_path(StdPatch::ToStdPath(u8_process_path));
u8_process_name = StdPatch::ToUTF8Path(process_path.filename()); u8_process_name = StdPatch::ToUTF8Path(process_path.filename());
} }
// then get process id // then get process id
@ -478,7 +478,7 @@ namespace YYCC::ExceptionHelper {
if (!WinFctHelper::GetLocalAppData(u8_localappdata_path)) if (!WinFctHelper::GetLocalAppData(u8_localappdata_path))
return false; return false;
// convert to std::filesystem::path // convert to std::filesystem::path
std::filesystem::path crash_report_path(StdPatch::ToStdPath(u8_localappdata_path.c_str())); std::filesystem::path crash_report_path(StdPatch::ToStdPath(u8_localappdata_path));
// slash into crash report folder // slash into crash report folder
crash_report_path /= StdPatch::ToStdPath(YYCC_U8("CrashDumps")); crash_report_path /= StdPatch::ToStdPath(YYCC_U8("CrashDumps"));
// use create function to make sure it is existing // use create function to make sure it is existing
@ -486,8 +486,8 @@ namespace YYCC::ExceptionHelper {
// build log path and coredump path // build log path and coredump path
// build std::filesystem::path first // build std::filesystem::path first
std::filesystem::path log_filepath = crash_report_path / StdPatch::ToStdPath(u8_log_filename.c_str()); std::filesystem::path log_filepath = crash_report_path / StdPatch::ToStdPath(u8_log_filename);
std::filesystem::path coredump_filepath = crash_report_path / StdPatch::ToStdPath(u8_coredump_filename.c_str()); std::filesystem::path coredump_filepath = crash_report_path / StdPatch::ToStdPath(u8_coredump_filename);
// output to result // output to result
log_path = StdPatch::ToUTF8Path(log_filepath); log_path = StdPatch::ToUTF8Path(log_filepath);
coredump_path = StdPatch::ToUTF8Path(coredump_filepath); coredump_path = StdPatch::ToUTF8Path(coredump_filepath);

View File

@ -77,7 +77,7 @@ namespace YYCC::StdPatch {
*/ */
template<class CharT, class Traits = std::char_traits<CharT>> template<class CharT, class Traits = std::char_traits<CharT>>
bool EndsWith(const std::basic_string_view<CharT, Traits>& that, std::basic_string_view<CharT, Traits> sv) noexcept { bool EndsWith(const std::basic_string_view<CharT, Traits>& that, std::basic_string_view<CharT, Traits> sv) noexcept {
return that.size() >= sv.size() && that.compare(that.size() - sv.size(), std::basic_string_view<CharT, Traits>::npos, sv); return that.size() >= sv.size() && that.compare(that.size() - sv.size(), std::basic_string_view<CharT, Traits>::npos, sv) == 0;
} }
/** /**
* @brief Checks if the string view ends with the given suffix * @brief Checks if the string view ends with the given suffix

View File

@ -1,5 +1,7 @@
#include <YYCCommonplace.hpp> #include <YYCCommonplace.hpp>
#include <cstdio> #include <cstdio>
#include <set>
#include <map>
namespace Console = YYCC::ConsoleHelper; namespace Console = YYCC::ConsoleHelper;
@ -346,7 +348,8 @@ namespace YYCCTestbench {
).c_str(), ).c_str(),
L"Fatal Error", MB_OK + MB_ICONERROR L"Fatal Error", MB_OK + MB_ICONERROR
); );
}); }
);
// Perform a div zero exception. // Perform a div zero exception.
#if defined (YYCC_DEBUG_UE_FILTER) #if defined (YYCC_DEBUG_UE_FILTER)
@ -355,8 +358,7 @@ namespace YYCCTestbench {
// all of code normally inside of main or WinMain here... // all of code normally inside of main or WinMain here...
int i = 1, j = 0; int i = 1, j = 0;
int k = i / j; int k = i / j;
} } __except (YYCC::ExceptionHelper::DebugCallUExceptionImpl(GetExceptionInformation())) {
__except (YYCC::ExceptionHelper::DebugCallUExceptionImpl(GetExceptionInformation())) {
OutputDebugStringW(L"executed filter function\n"); OutputDebugStringW(L"executed filter function\n");
} }
#else #else
@ -388,29 +390,50 @@ namespace YYCCTestbench {
Assert(YYCC::WinFctHelper::GetLocalAppData(test_localappdata_path), YYCC_U8("YYCC::WinFctHelper::GetLocalAppData")); Assert(YYCC::WinFctHelper::GetLocalAppData(test_localappdata_path), YYCC_U8("YYCC::WinFctHelper::GetLocalAppData"));
Console::FormatLine(YYCC_U8("Local AppData: %s"), test_localappdata_path.c_str()); Console::FormatLine(YYCC_U8("Local AppData: %s"), test_localappdata_path.c_str());
Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(1252)) == true, YYCC_U8("YYCC::WinFctHelper::IsValidCodePage")); Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(1252)), YYCC_U8("YYCC::WinFctHelper::IsValidCodePage"));
Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(114514)) == false, YYCC_U8("YYCC::WinFctHelper::IsValidCodePage")); Assert(!YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(114514)), YYCC_U8("YYCC::WinFctHelper::IsValidCodePage"));
// MARK: There is no testbench for MoveFile, CopyFile DeleteFile.
// Because they can operate file system files.
// And may cause test environment entering unstable status.
#endif #endif
} }
static void StdPatch() { static void StdPatch() {
// Std Path
std::filesystem::path test_path; std::filesystem::path test_path;
for (const auto& strl : c_UTF8TestStrTable) { for (const auto& strl : c_UTF8TestStrTable) {
test_path /= YYCC::StdPatch::ToStdPath(strl.c_str()); test_path /= YYCC::StdPatch::ToStdPath(strl);
} }
YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path)); YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path));
#if YYCC_OS == YYCC_OS_WINDOWS #if YYCC_OS == YYCC_OS_WINDOWS
std::wstring wdecilmer(1u, std::filesystem::path::preferred_separator); std::wstring wdecilmer(1u, std::filesystem::path::preferred_separator);
YYCC::yycc_u8string decilmer(YYCC::EncodingHelper::WcharToUTF8(wdecilmer.c_str())); YYCC::yycc_u8string decilmer(YYCC::EncodingHelper::WcharToUTF8(wdecilmer));
#else #else
YYCC::yycc_u8string decilmer(1u, std::filesystem::path::preferred_separator); YYCC::yycc_u8string decilmer(1u, std::filesystem::path::preferred_separator);
#endif #endif
YYCC::yycc_u8string test_joined_path(YYCC::StringHelper::Join(c_UTF8TestStrTable, decilmer.c_str())); YYCC::yycc_u8string test_joined_path(YYCC::StringHelper::Join(c_UTF8TestStrTable, decilmer.c_str()));
Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::StdPatch")); Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::StdPatch::ToStdPath, YYCC::StdPatch::ToUTF8Path"));
// StartsWith, EndsWith
YYCC::yycc_u8string test_starts_ends_with(YYCC_U8("aaabbbccc"));
Assert(YYCC::StdPatch::StartsWith(test_starts_ends_with, YYCC_U8("aaa")), YYCC_U8("YYCC::StdPatch::StartsWith"));
Assert(!YYCC::StdPatch::StartsWith(test_starts_ends_with, YYCC_U8("ccc")), YYCC_U8("YYCC::StdPatch::StartsWith"));
Assert(!YYCC::StdPatch::EndsWith(test_starts_ends_with, YYCC_U8("aaa")), YYCC_U8("YYCC::StdPatch::EndsWith"));
Assert(YYCC::StdPatch::EndsWith(test_starts_ends_with, YYCC_U8("ccc")), YYCC_U8("YYCC::StdPatch::EndsWith"));
// Contains
std::set<int> test_set { 1, 2, 3, 4, 6, 7 };
Assert(YYCC::StdPatch::Contains(test_set, static_cast<int>(1)), YYCC_U8("YYCC::StdPatch::Contains"));
Assert(!YYCC::StdPatch::Contains(test_set, static_cast<int>(5)), YYCC_U8("YYCC::StdPatch::Contains"));
std::map<int, float> test_map { { 1, 1.0f }, { 4, 4.0f } };
Assert(YYCC::StdPatch::Contains(test_map, static_cast<int>(1)), YYCC_U8("YYCC::StdPatch::Contains"));
Assert(!YYCC::StdPatch::Contains(test_map, static_cast<int>(5)), YYCC_U8("YYCC::StdPatch::Contains"));
} }