ending_retirement_test.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include <array>
  2. #include <cassert>
  3. #include "../Sunrise/src/client/hooks/ember_movies/readiness_rules.h"
  4. #include "../Sunrise/src/client/hooks/ember_movies/sunburn_rules.h"
  5. #include "../Sunrise/src/client/hooks/ember_movies/playback_rules.h"
  6. #include "../Sunrise/src/client/hooks/mission_retirement/mission_retirement.h"
  7. #include "../Sunrise/src/middleware/bap/activity_message/roster_presence.h"
  8. #include "../Sunrise/src/middleware/encoding/bit_reader.h"
  9. #include "../Sunrise/src/state/activity/membership/teleport_rules.h"
  10. #include "../Sunrise/src/core/logging/log.h"
  11. namespace sunrise::core::log {
  12. bool accepts(Channel, Level) noexcept { return false; }
  13. void write(Channel, Level, std::string_view) noexcept {}
  14. }
  15. namespace wire = sunrise::middleware::bap::activity_message::sensor_auth_update;
  16. namespace retire = sunrise::client::hooks::mission_retirement;
  17. namespace member = sunrise::state::activity::membership;
  18. using sunrise::middleware::encoding::bits::Reader;
  19. static void expect(Reader& reader, unsigned width, std::uint64_t expected) {
  20. std::uint64_t value{};
  21. assert(reader.read(static_cast<std::uint8_t>(width), value) && value == expected);
  22. }
  23. int main() {
  24. namespace movies=sunrise::client::hooks::ember_movies;
  25. // Native kind 2 resolves shared-tag records; these ordinary movie tags require 1.
  26. static_assert(movies::movie_resource_kind==1);
  27. assert((movies::movie_metadata(0x80BCA001)==std::array<std::uint32_t,4>{0x80BCA001,0x80BCA000,0x80B9EB33,0x80BCA032}));
  28. assert((movies::movie_metadata(0x80BCA003)==std::array<std::uint32_t,4>{0x80BCA003,0x80BCA002,0x80B9EB34,0x80BCA032}));
  29. assert((movies::movie_metadata(0x80BCA034)==std::array<std::uint32_t,4>{})); // media is not a wrapper
  30. assert(movies::movie_stream(0x80BCA001)==0x80BCA034);
  31. assert(movies::movie_stream(0x80BCA003)==0x80C7C000);
  32. assert(movies::movie_stream(0x80BCA000)==0xFFFFFFFF);
  33. // The 13f07ee capture: metadata was loaded, but the video stream still held a
  34. // free-list entry (FEFE0035, 0, location 0). Native CRI entered error state 7.
  35. assert(!movies::movie_stream_ready(0xFEFE0035,0,0));
  36. assert(movies::movie_stream_ready(0xE80779A0,0x41363B,0x10000005));
  37. assert(!movies::movie_stream_ready(0xC0000000,0x41363B,0x10000005));
  38. assert(!movies::movie_stream_ready(0x280779A0,0x41363B,0x10000005));
  39. assert(!movies::movie_stream_ready(0xE80779A0,0x40103B,0x10000005));
  40. assert(!movies::movie_stream_ready(0xE80779A0,0x41363B,0));
  41. assert(!movies::movie_stream_ready(0xE80779A0,0x41363B,0x100000005ULL));
  42. // Captured crash: registered movie tags contain free-list entries, not resident headers.
  43. assert(!movies::movie_resources_ready(1,0x80BCA001,false,0,false,0xFFFFFFFF));
  44. assert(!movies::movie_resources_ready(2,0x80BCA001,false,0x80BCA000,true,0x80BCA034));
  45. assert(!movies::movie_resources_ready(2,0x80BCA001,true,0x80BCA000,false,0x80BCA034));
  46. assert(!movies::movie_resources_ready(2,0x80BCA001,true,0x80BCA002,true,0x80BCA034));
  47. assert(!movies::movie_resources_ready(3,0x80BCA001,true,0x80BCA000,true,0x80BCA034));
  48. assert(!movies::movie_resources_ready(2,0x80BCA001,true,0x80BCA000,true,0xFFFFFFFF));
  49. assert(movies::movie_resources_ready(2,0x80BCA001,true,0x80BCA000,true,0x80BCA034));
  50. assert(movies::movie_resources_ready(2,0x80BCA003,true,0x80BCA002,true,0x80C7C000));
  51. assert(!movies::resource_can_release(0) && !movies::resource_can_release(1));
  52. assert(movies::resource_can_release(2) && movies::resource_can_release(3));
  53. // Only Ember slot 43 may borrow sunburn. The global Foundry effect and rail shock stay distinct.
  54. assert(movies::ember_burn_source(0x80B3C0C6,0x80809540,0xAC8,0x80C1D9E0));
  55. assert(!movies::ember_burn_source(0x80BEB26F,0x80809540,0xAC8,0x80C1D9E0));
  56. assert(!movies::ember_burn_source(0x80B3C0C6,0x8080953F,0xAC8,0x80C1D9E0));
  57. assert(!movies::ember_burn_source(0x80B3C0C6,0x80809540,0xAC0,0x80C1D9E0));
  58. assert(!movies::ember_burn_source(0x80B3C0C6,0x80809540,0xAC8,0x80C1D389));
  59. movies::Playback playback;
  60. assert(playback.observe(false,5,true)==movies::Status::preparing);
  61. assert(playback.observe(true,0,false)==movies::Status::preparing);
  62. assert(playback.observe(true,6,false)==movies::Status::preparing);
  63. assert(playback.observe(true,3,true)==movies::Status::preparing);
  64. assert(playback.observe(true,5,true)==movies::Status::playing);
  65. assert(playback.observe(true,6,true)==movies::Status::playing);
  66. assert(playback.observe(true,6,false)==movies::Status::complete);
  67. assert(playback.observe(false,6,false)==movies::Status::failed);
  68. assert(playback.observe(true,7,false)==movies::Status::failed);
  69. movies::Playback skipped;
  70. assert(skipped.observe(true,5,true)==movies::Status::playing);
  71. assert(skipped.observe(true,0,false)==movies::Status::complete);
  72. std::array<std::uint32_t, 5> history{102, 103, 104};
  73. std::size_t historyCount = 3;
  74. const std::array<std::uint32_t, 3> movieOne{105, 102, 104};
  75. const std::array<std::uint32_t, 3> movieTwo{106, 105, 104};
  76. assert(wire::extend_key_order(history, historyCount, movieOne));
  77. assert(wire::extend_key_order(history, historyCount, movieTwo));
  78. assert(historyCount == 5 && (history == std::array<std::uint32_t, 5>{102,103,104,105,106}));
  79. assert(wire::extend_key_order(history, historyCount, movieOne));
  80. const std::array<std::uint32_t, 1> overflow{107};
  81. assert(!wire::extend_key_order(history, historyCount, overflow));
  82. // Unknown/empty worlds and a different owner cannot masquerade as cleanup.
  83. retire::Progress progress{retire::Status::baselinePending, 0};
  84. progress.observe(0, 1234, 4, 0);
  85. assert(progress.value == retire::Status::baselinePending);
  86. progress.observe(0, 1234, 8, 4);
  87. assert(progress.value == retire::Status::retiring);
  88. progress.observe(1, 1234, 4, 0);
  89. progress.observe(0, 5678, 4, 0);
  90. progress.observe(0, 1234, 0, 0);
  91. progress.observe(0, 1234, 5, 1);
  92. assert(progress.value == retire::Status::retiring);
  93. progress.observe(0, 1234, 4, 0);
  94. assert(progress.value == retire::Status::complete);
  95. // Exercise the actual encoder: old keys retain their ordinal, a clear bit removes
  96. // only the retired key, and phase two contains no body for that removed group.
  97. static wire::Snapshot snapshot{};
  98. std::array<std::uint8_t, 1> types{1}, flags{0};
  99. std::array<std::uint16_t, 1> indices{0};
  100. std::array<std::uint32_t, 3> keys{102, 103, 104};
  101. std::array<wire::BubbleSubBlock, 1> blocks{{{0, keys}}};
  102. snapshot.roster.groupCount = 4; snapshot.roster.topLevelGroupCount = 1;
  103. snapshot.roster.bubbleSubBlocks = blocks;
  104. for (unsigned i = 0; i < 4; ++i) {
  105. auto& group = snapshot.roster.groups[i];
  106. group.key = 101 + i; group.slotTypes = types; group.slotFlags = flags; group.slotIndices = indices;
  107. }
  108. snapshot.roster.groups[2].retired = true;
  109. std::array<std::byte, 4096> bytes{}; std::size_t size{};
  110. assert(wire::encode_sensor_auth_update(snapshot, bytes, size));
  111. Reader mask{std::span(bytes).first(size)};
  112. assert(mask.skip(wire::kLatchBitWithoutGrant + 1 + wire::delta_bits(1, {}) - 1));
  113. expect(mask, 1, 1); expect(mask, 7, 1); // Field one, one bubble.
  114. expect(mask, 1, 1); expect(mask, 32, 0x80000000U);
  115. expect(mask, 1, 1); expect(mask, 1, 1); expect(mask, 7, 3);
  116. for (auto key : keys) expect(mask, 32, key);
  117. expect(mask, 1, 1); expect(mask, 32, 5); // Keep ordinals 0 and 2.
  118. expect(mask, 32, 0); expect(mask, 32, 0);
  119. Reader bodies{std::span(bytes).first(size)};
  120. assert(bodies.skip(wire::kLatchBitWithoutGrant + 1 + wire::delta_bits(1, blocks)));
  121. for (auto key : {101U, 102U, 104U}) {
  122. expect(bodies, 1, 1); expect(bodies, 32, key); expect(bodies, 32, 0);
  123. expect(bodies, 1, 1); expect(bodies, 32, key); expect(bodies, 7, 2);
  124. expect(bodies, 16, 32768); expect(bodies, 32, 0); expect(bodies, 1, 0);
  125. }
  126. expect(bodies, 1, 0); expect(bodies, 1, 0);
  127. snapshot.roster.groups[0].retired = true;
  128. assert(!wire::encode_sensor_auth_update(snapshot, bytes, size));
  129. member::MembershipState state{};
  130. state.hasHostTeleport = true; state.hostTeleportQualified = true;
  131. state.hostTeleport = {1, 8, 1, 123}; state.teleport = {2, 8, 1, 123};
  132. state.region.index = 1; state.currentReported = true; state.currentRegion.index = 0;
  133. member::observe_qualified_teleport(state);
  134. assert(state.hostTeleport.state == 1); // Pending-region advertisement is not arrival.
  135. state.teleport.state = 3; state.currentRegion.index = 1;
  136. state.teleport.sliceSetHash = 124;
  137. member::observe_qualified_teleport(state); assert(state.hostTeleport.state == 1);
  138. state.teleport.sliceSetHash = 123; state.teleport.token = 7;
  139. member::observe_qualified_teleport(state); assert(state.hostTeleport.state == 1);
  140. state.teleport.token = 8;
  141. member::observe_qualified_teleport(state); assert(state.hostTeleport.state == 3);
  142. state.teleport.state = 0;
  143. member::observe_qualified_teleport(state); assert(!state.hasHostTeleport);
  144. assert(member::next_teleport_token(255) == 1 && member::next_teleport_token(8) == 9);
  145. }