diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 9efc5925..a63db430 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -17,377 +17,380 @@ using namespace std::literals; // to trick compiler optimizations __declspec(dllexport) bool do_the_task = true; -struct tls_struct +namespace { - DWORD num = 1337; - - tls_struct() + struct tls_struct { - num = GetCurrentThreadId(); - } -}; + DWORD num = 1337; -thread_local tls_struct tls_var{}; + tls_struct() + { + num = GetCurrentThreadId(); + } + }; -// getenv is broken right now :( -std::string read_env(const char* env) -{ - char buffer[0x1000] = {}; - if (!GetEnvironmentVariableA(env, buffer, sizeof(buffer))) + thread_local tls_struct tls_var{}; + + // getenv is broken right now :( + std::string read_env(const char* env) { - return {}; + char buffer[0x1000] = {}; + if (!GetEnvironmentVariableA(env, buffer, sizeof(buffer))) + { + return {}; + } + + return buffer; } - return buffer; -} - -bool test_threads() -{ - constexpr auto thread_count = 5ULL; - - std::atomic counter{0}; - - std::vector threads{}; - threads.reserve(thread_count); - - for (auto i = 0ULL; i < thread_count; ++i) + bool test_threads() { - threads.emplace_back([&counter] { - ++counter; - std::this_thread::yield(); - ++counter; - // Host scheduling/cpu performance can have impact on emulator scheduling - // std::this_thread::sleep_for(std::chrono::milliseconds(100)); - ++counter; - }); - } + constexpr auto thread_count = 5ULL; - for (auto& t : threads) - { - t.join(); - } + std::atomic counter{0}; - return counter == (thread_count * 3ULL); -} + std::vector threads{}; + threads.reserve(thread_count); -bool test_tls() -{ - std::atomic_bool kill{false}; - std::atomic_uint32_t successes{0}; - constexpr uint32_t thread_count = 2; - - std::vector ts{}; - kill = false; - - for (size_t i = 0; i < thread_count; ++i) - { - ts.emplace_back([&] { - while (!kill) - { + for (auto i = 0ULL; i < thread_count; ++i) + { + threads.emplace_back([&counter] { + ++counter; std::this_thread::yield(); - } + ++counter; + // Host scheduling/cpu performance can have impact on emulator scheduling + // std::this_thread::sleep_for(std::chrono::milliseconds(100)); + ++counter; + }); + } - if (tls_var.num == GetCurrentThreadId()) - { - ++successes; - } - }); - } - - LoadLibraryA("d3dcompiler_47.dll"); - LoadLibraryA("dsound.dll"); - LoadLibraryA("comctl32.dll"); - /*LoadLibraryA("d3d9.dll"); - LoadLibraryA("dxgi.dll"); - LoadLibraryA("wlanapi.dll");*/ - - kill = true; - - for (auto& t : ts) - { - if (t.joinable()) + for (auto& t : threads) { t.join(); } + + return counter == (thread_count * 3ULL); } - return successes == thread_count; -} - -bool test_env() -{ - const auto computername = read_env("COMPUTERNAME"); - - SetEnvironmentVariableA("BLUB", "LUL"); - - const auto blub = read_env("BLUB"); - - return !computername.empty() && blub == "LUL"; -} - -bool test_file_path_io(const std::filesystem::path& filename) -{ - std::error_code ec{}; - const auto absolute_file = std::filesystem::absolute(filename, ec); - - if (ec) + bool test_tls() { - puts("Getting absolute path failed"); - return false; - } + std::atomic_bool kill{false}; + std::atomic_uint32_t successes{0}; + constexpr uint32_t thread_count = 2; - const auto canonical_file = std::filesystem::canonical(filename, ec); - (void)canonical_file; + std::vector ts{}; + kill = false; - if (ec) - { - puts("Getting canonical path failed"); - return false; - } - - return true; -} - -bool test_io() -{ - const std::filesystem::path filename1 = "a.txt"; - const std::filesystem::path filename2 = "A.tXt"; - - FILE* fp{}; - (void)fopen_s(&fp, filename1.string().c_str(), "wb"); - - if (!fp) - { - puts("Bad file"); - return false; - } - - const std::string text = "Blub"; - - (void)fwrite(text.data(), 1, text.size(), fp); - (void)fclose(fp); - - if (!test_file_path_io(filename1)) - { - return false; - } - - std::ifstream t(filename2); - t.seekg(0, std::ios::end); - const size_t size = t.tellg(); - std::string buffer(size, ' '); - t.seekg(0); - t.read(buffer.data(), static_cast(size)); - - return text == buffer; -} - -bool test_working_directory() -{ - std::error_code ec{}; - - const auto current_dir = std::filesystem::current_path(ec); - if (ec) - { - puts("Failed to get current path"); - return false; - } - - const std::filesystem::path sys32 = "C:/windows/system32"; - current_path(sys32, ec); - - if (ec) - { - puts("Failed to update working directory"); - return false; - } - - const auto new_current_dir = std::filesystem::current_path(); - if (sys32 != new_current_dir) - { - puts("Updated directory is wrong!"); - return false; - } - - if (!std::ifstream("ntdll.dll")) - { - puts("Working directory is not active!"); - return false; - } - - std::filesystem::current_path(current_dir); - return std::filesystem::current_path() == current_dir; -} - -bool test_dir_io() -{ - size_t count = 0; - - for (auto i : std::filesystem::directory_iterator(R"(C:\Windows\System32\)")) - { - ++count; - if (count > 30) + for (size_t i = 0; i < thread_count; ++i) { - return true; + ts.emplace_back([&] { + while (!kill) + { + std::this_thread::yield(); + } + + if (tls_var.num == GetCurrentThreadId()) + { + ++successes; + } + }); + } + + LoadLibraryA("d3dcompiler_47.dll"); + LoadLibraryA("dsound.dll"); + LoadLibraryA("comctl32.dll"); + /*LoadLibraryA("d3d9.dll"); + LoadLibraryA("dxgi.dll"); + LoadLibraryA("wlanapi.dll");*/ + + kill = true; + + for (auto& t : ts) + { + if (t.joinable()) + { + t.join(); + } + } + + return successes == thread_count; + } + + bool test_env() + { + const auto computername = read_env("COMPUTERNAME"); + + SetEnvironmentVariableA("BLUB", "LUL"); + + const auto blub = read_env("BLUB"); + + return !computername.empty() && blub == "LUL"; + } + + bool test_file_path_io(const std::filesystem::path& filename) + { + std::error_code ec{}; + const auto absolute_file = std::filesystem::absolute(filename, ec); + + if (ec) + { + puts("Getting absolute path failed"); + return false; + } + + const auto canonical_file = std::filesystem::canonical(filename, ec); + (void)canonical_file; + + if (ec) + { + puts("Getting canonical path failed"); + return false; + } + + return true; + } + + bool test_io() + { + const std::filesystem::path filename1 = "a.txt"; + const std::filesystem::path filename2 = "A.tXt"; + + FILE* fp{}; + (void)fopen_s(&fp, filename1.string().c_str(), "wb"); + + if (!fp) + { + puts("Bad file"); + return false; + } + + const std::string text = "Blub"; + + (void)fwrite(text.data(), 1, text.size(), fp); + (void)fclose(fp); + + if (!test_file_path_io(filename1)) + { + return false; + } + + std::ifstream t(filename2); + t.seekg(0, std::ios::end); + const size_t size = t.tellg(); + std::string buffer(size, ' '); + t.seekg(0); + t.read(buffer.data(), static_cast(size)); + + return text == buffer; + } + + bool test_working_directory() + { + std::error_code ec{}; + + const auto current_dir = std::filesystem::current_path(ec); + if (ec) + { + puts("Failed to get current path"); + return false; + } + + const std::filesystem::path sys32 = "C:/windows/system32"; + current_path(sys32, ec); + + if (ec) + { + puts("Failed to update working directory"); + return false; + } + + const auto new_current_dir = std::filesystem::current_path(); + if (sys32 != new_current_dir) + { + puts("Updated directory is wrong!"); + return false; + } + + if (!std::ifstream("ntdll.dll")) + { + puts("Working directory is not active!"); + return false; + } + + std::filesystem::current_path(current_dir); + return std::filesystem::current_path() == current_dir; + } + + bool test_dir_io() + { + size_t count = 0; + + for (auto i : std::filesystem::directory_iterator(R"(C:\Windows\System32\)")) + { + ++count; + if (count > 30) + { + return true; + } + } + + return count > 30; + } + + std::optional read_registry_string(const HKEY root, const char* path, const char* value) + { + HKEY key{}; + if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS) + { + return std::nullopt; + } + + char data[MAX_PATH]{}; + DWORD length = sizeof(data); + const auto res = RegQueryValueExA(key, value, nullptr, nullptr, reinterpret_cast(data), &length); + + if (RegCloseKey(key) != ERROR_SUCCESS) + { + return std::nullopt; + } + + if (res != ERROR_SUCCESS) + { + return std::nullopt; + } + + if (length == 0) + { + return ""; + } + + return {std::string(data, std::min(static_cast(length - 1), sizeof(data)))}; + } + + bool test_registry() + { + const auto val = + read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", "ProgramFilesDir"); + if (!val) + { + return false; + } + + return *val == "C:\\Program Files"; + } + + void throw_exception() + { + if (do_the_task) + { + throw std::runtime_error("OK"); } } - return count > 30; -} - -std::optional read_registry_string(const HKEY root, const char* path, const char* value) -{ - HKEY key{}; - if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS) + bool test_exceptions() { - return std::nullopt; + try + { + throw_exception(); + return false; + } + catch (const std::exception& e) + { + return e.what() == std::string("OK"); + } } - char data[MAX_PATH]{}; - DWORD length = sizeof(data); - const auto res = RegQueryValueExA(key, value, nullptr, nullptr, reinterpret_cast(data), &length); - - if (RegCloseKey(key) != ERROR_SUCCESS) + bool test_socket() { - return std::nullopt; + network::udp_socket receiver{AF_INET}; + const network::udp_socket sender{AF_INET}; + const network::address destination{"127.0.0.1:28970", AF_INET}; + constexpr std::string_view send_data = "Hello World"; + + if (!receiver.bind(destination)) + { + puts("Failed to bind socket!"); + return false; + } + + if (!sender.send(destination, send_data)) + { + puts("Failed to send data!"); + return false; + } + + const auto response = receiver.receive(); + + if (!response) + { + puts("Failed to recieve data!"); + return false; + } + + return send_data == response->second; } - if (res != ERROR_SUCCESS) + void throw_access_violation() { - return std::nullopt; + if (do_the_task) + { + *reinterpret_cast(1) = 1; + } } - if (length == 0) + bool test_access_violation_exception() { - return ""; + __try + { + throw_access_violation(); + return false; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode() == STATUS_ACCESS_VIOLATION; + } } - return {std::string(data, std::min(static_cast(length - 1), sizeof(data)))}; -} - -bool test_registry() -{ - const auto val = - read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", "ProgramFilesDir"); - if (!val) + bool test_ud2_exception(void* address) { - return false; + __try + { + reinterpret_cast(address)(); + return false; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION; + } } - return *val == "C:\\Program Files"; -} - -void throw_exception() -{ - if (do_the_task) + bool test_illegal_instruction_exception() { - throw std::runtime_error("OK"); - } -} + const auto address = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (!address) + { + return false; + } -bool test_exceptions() -{ - try - { - throw_exception(); - return false; - } - catch (const std::exception& e) - { - return e.what() == std::string("OK"); - } -} + memcpy(address, "\x0F\x0B", 2); // ud2 -bool test_socket() -{ - network::udp_socket receiver{AF_INET}; - const network::udp_socket sender{AF_INET}; - const network::address destination{"127.0.0.1:28970", AF_INET}; - constexpr std::string_view send_data = "Hello World"; + const auto res = test_ud2_exception(address); - if (!receiver.bind(destination)) - { - puts("Failed to bind socket!"); - return false; + VirtualFree(address, 0x1000, MEM_RELEASE); + + return res; } - if (!sender.send(destination, send_data)) + bool test_native_exceptions() { - puts("Failed to send data!"); - return false; + return test_access_violation_exception() && test_illegal_instruction_exception(); } - const auto response = receiver.receive(); - - if (!response) + void print_time() { - puts("Failed to recieve data!"); - return false; + const auto epoch_time = std::chrono::system_clock::now().time_since_epoch(); + printf("Time: %lld\n", std::chrono::duration_cast(epoch_time).count()); } - - return send_data == response->second; -} - -void throw_access_violation() -{ - if (do_the_task) - { - *reinterpret_cast(1) = 1; - } -} - -bool test_access_violation_exception() -{ - __try - { - throw_access_violation(); - return false; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode() == STATUS_ACCESS_VIOLATION; - } -} - -bool test_ud2_exception(void* address) -{ - __try - { - reinterpret_cast(address)(); - return false; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION; - } -} - -bool test_illegal_instruction_exception() -{ - const auto address = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (!address) - { - return false; - } - - memcpy(address, "\x0F\x0B", 2); // ud2 - - const auto res = test_ud2_exception(address); - - VirtualFree(address, 0x1000, MEM_RELEASE); - - return res; -} - -bool test_native_exceptions() -{ - return test_access_violation_exception() && test_illegal_instruction_exception(); -} - -void print_time() -{ - const auto epoch_time = std::chrono::system_clock::now().time_since_epoch(); - printf("Time: %lld\n", std::chrono::duration_cast(epoch_time).count()); } #define RUN_TEST(func, name) \