settings_regression_tests.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include <Windows.h>
  2. #include <array>
  3. #include <crtdbg.h>
  4. #include <cstdint>
  5. #include <cstdio>
  6. #include <string_view>
  7. #include "core/settings/settings.h"
  8. #include "state/account/inventory/item_state.h"
  9. namespace sunrise::core::log {
  10. Settings defaults() noexcept {
  11. return {};
  12. }
  13. void early(std::string_view) noexcept {}
  14. void write(Channel, Level, std::string_view) noexcept {}
  15. } // namespace sunrise::core::log
  16. namespace sunrise::state::activity::defaults {
  17. ActivityDefaults authored() noexcept {
  18. return {};
  19. }
  20. bool valid(const DefaultDestination&) noexcept {
  21. return true;
  22. }
  23. bool valid(const ActivityDefaults&) noexcept {
  24. return true;
  25. }
  26. } // namespace sunrise::state::activity::defaults
  27. namespace sunrise::state::entitlements {
  28. Table authored() noexcept {
  29. return {};
  30. }
  31. bool valid(const Entitlement&) noexcept {
  32. return true;
  33. }
  34. bool valid(const Table&) noexcept {
  35. return true;
  36. }
  37. } // namespace sunrise::state::entitlements
  38. namespace sunrise::state::account {
  39. bool valid_authored(const AccountState&) noexcept {
  40. return true;
  41. }
  42. } // namespace sunrise::state::account
  43. namespace sunrise::state::account::settings {
  44. bool valid(const AccountSettings&) noexcept {
  45. return true;
  46. }
  47. } // namespace sunrise::state::account::settings
  48. int failures{};
  49. namespace {
  50. void expect(bool value, const char* label) noexcept {
  51. if (!value) {
  52. std::fprintf(stderr, "FAIL %s\n", label);
  53. ++failures;
  54. }
  55. }
  56. bool parse_catalyst_policy(std::string_view json, bool& output) noexcept {
  57. sunrise::core::settings::Settings settings{};
  58. if (!sunrise::core::settings::parse(json, settings)) {
  59. return false;
  60. }
  61. output = settings.completeExoticCatalysts;
  62. return true;
  63. }
  64. void test_item_state_contract() noexcept {
  65. for (std::uint32_t flags = 0; flags <= 0x7U; ++flags) {
  66. expect(sunrise::state::account::inventory::valid_item_state(flags),
  67. "known item-state bits are valid");
  68. }
  69. expect(!sunrise::state::account::inventory::valid_item_state(0x8U),
  70. "unknown item-state bits are invalid");
  71. }
  72. void test_optional_catalyst_policy() noexcept {
  73. bool enabled = false;
  74. expect(sunrise::core::settings::kSettingsVersion == 8,
  75. "optional catalyst key keeps settings version 8");
  76. expect(parse_catalyst_policy(R"({"version":8})", enabled) && enabled,
  77. "version 8 without catalyst key keeps the true default");
  78. expect(parse_catalyst_policy(R"({"version":8,"complete_exotic_catalysts":false})", enabled)
  79. && !enabled,
  80. "version 8 accepts an explicit false catalyst policy");
  81. expect(
  82. !parse_catalyst_policy(
  83. R"({"version":8,"complete_exotic_catalysts":true,"complete_exotic_catalysts":false})",
  84. enabled),
  85. "duplicate catalyst policy is rejected");
  86. expect(!parse_catalyst_policy(R"({"version":8,"complete_exotic_catalysts":1})", enabled),
  87. "non-boolean catalyst policy is rejected");
  88. }
  89. void test_settings_file_round_trip() noexcept {
  90. constexpr std::string_view document = R"({"version":8,"complete_exotic_catalysts":false})";
  91. std::array<char, MAX_PATH + 1> directory{};
  92. std::array<char, MAX_PATH + 1> path{};
  93. const DWORD directoryLength =
  94. GetTempPathA(static_cast<DWORD>(directory.size()), directory.data());
  95. if (directoryLength == 0 || directoryLength >= directory.size()
  96. || GetTempFileNameA(directory.data(), "sun", 0, path.data()) == 0) {
  97. expect(false, "settings round trip creates a temporary file");
  98. return;
  99. }
  100. HANDLE file = CreateFileA(
  101. path.data(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, nullptr);
  102. DWORD written = 0;
  103. const bool saved =
  104. file != INVALID_HANDLE_VALUE
  105. && WriteFile(file, document.data(), static_cast<DWORD>(document.size()), &written, nullptr)
  106. && written == document.size();
  107. if (file != INVALID_HANDLE_VALUE) {
  108. CloseHandle(file);
  109. }
  110. std::array<char, 128> reloaded{};
  111. file = CreateFileA(path.data(),
  112. GENERIC_READ,
  113. FILE_SHARE_READ,
  114. nullptr,
  115. OPEN_EXISTING,
  116. FILE_ATTRIBUTE_NORMAL,
  117. nullptr);
  118. DWORD read = 0;
  119. const bool loaded =
  120. file != INVALID_HANDLE_VALUE
  121. && ReadFile(file, reloaded.data(), static_cast<DWORD>(reloaded.size()), &read, nullptr)
  122. && read == document.size();
  123. if (file != INVALID_HANDLE_VALUE) {
  124. CloseHandle(file);
  125. }
  126. DeleteFileA(path.data());
  127. bool enabled = true;
  128. expect(saved && loaded
  129. && parse_catalyst_policy(std::string_view{reloaded.data(), read}, enabled)
  130. && !enabled,
  131. "settings file round trip preserves the catalyst policy");
  132. }
  133. } // namespace
  134. void test_exotic_catalysts() noexcept;
  135. void test_resolved_catalyst_output() noexcept;
  136. void test_opcode406_item_state() noexcept;
  137. int main() {
  138. #if defined(_DEBUG)
  139. _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
  140. _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
  141. #endif
  142. test_item_state_contract();
  143. test_optional_catalyst_policy();
  144. test_settings_file_round_trip();
  145. test_opcode406_item_state();
  146. test_exotic_catalysts();
  147. test_resolved_catalyst_output();
  148. if (failures != 0) {
  149. std::fprintf(stderr, "%d regression test(s) failed\n", failures);
  150. return 1;
  151. }
  152. std::puts("All regression tests passed");
  153. return 0;
  154. }