backing_mocks.hpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // Copyright 2022 Nick Brassel (@tzarc)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <algorithm>
  5. #include <array>
  6. #include <cstdint>
  7. #include <cstdlib>
  8. #include <functional>
  9. #include <type_traits>
  10. #include <vector>
  11. extern "C" {
  12. #include "fnv.h"
  13. #include "wear_leveling.h"
  14. #include "wear_leveling_internal.h"
  15. };
  16. // Maximum number of mock write log entries to keep
  17. using MOCK_WRITE_LOG_MAX_ENTRIES = std::integral_constant<std::size_t, 1024>;
  18. // Complement to the backing store integral, for emulating flash erases of all bytes=0xFF
  19. using BACKING_STORE_INTEGRAL_COMPLEMENT = std::integral_constant<backing_store_int_t, ((backing_store_int_t)(~(backing_store_int_t)0))>;
  20. // Total number of elements stored in the backing arrays
  21. using BACKING_STORE_ELEMENT_COUNT = std::integral_constant<std::size_t, (WEAR_LEVELING_BACKING_SIZE / sizeof(backing_store_int_t))>;
  22. class MockBackingStoreElement {
  23. private:
  24. backing_store_int_t value;
  25. std::size_t writes;
  26. std::size_t erases;
  27. public:
  28. MockBackingStoreElement() : value(BACKING_STORE_INTEGRAL_COMPLEMENT::value), writes(0), erases(0) {}
  29. void reset() {
  30. erase();
  31. writes = 0;
  32. erases = 0;
  33. }
  34. void erase() {
  35. if (!is_erased()) {
  36. ++erases;
  37. }
  38. value = BACKING_STORE_INTEGRAL_COMPLEMENT::value;
  39. }
  40. backing_store_int_t get() const {
  41. return value;
  42. }
  43. void set(const backing_store_int_t& v) {
  44. EXPECT_TRUE(is_erased()) << "Attempted write at index which isn't empty.";
  45. value = v;
  46. ++writes;
  47. }
  48. std::size_t num_writes() const {
  49. return writes;
  50. }
  51. std::size_t num_erases() const {
  52. return erases;
  53. }
  54. bool is_erased() const {
  55. return value == BACKING_STORE_INTEGRAL_COMPLEMENT::value;
  56. }
  57. };
  58. struct MockBackingStoreLogEntry {
  59. MockBackingStoreLogEntry(uint32_t address, backing_store_int_t value) : address(address), value(value), erased(false) {}
  60. MockBackingStoreLogEntry(bool erased) : address(0), value(0), erased(erased) {}
  61. uint32_t address = 0; // The address of the operation
  62. backing_store_int_t value = 0; // The value of the operation
  63. bool erased = false; // Whether the entire backing store was erased
  64. };
  65. class MockBackingStore {
  66. private:
  67. MockBackingStore() {
  68. reset_instance();
  69. }
  70. // Type containing each of the entries and the write counts
  71. using storage_t = std::array<MockBackingStoreElement, BACKING_STORE_ELEMENT_COUNT::value>;
  72. // Whether the backing store is locked
  73. bool locked;
  74. // The actual data stored in the emulated flash
  75. storage_t backing_storage;
  76. // The number of erase cycles that have occurred
  77. std::uint64_t backing_erasure_count;
  78. // The max number of writes to an element of the backing store
  79. std::uint64_t backing_max_write_count;
  80. // The total number of writes to all elements of the backing store
  81. std::uint64_t backing_total_write_count;
  82. // The write log for the backing store
  83. std::vector<MockBackingStoreLogEntry> write_log;
  84. // The number of times each API was invoked
  85. std::uint64_t backing_init_invoke_count;
  86. std::uint64_t backing_unlock_invoke_count;
  87. std::uint64_t backing_erase_invoke_count;
  88. std::uint64_t backing_write_invoke_count;
  89. std::uint64_t backing_lock_invoke_count;
  90. // Whether init should succeed
  91. std::function<bool(std::uint64_t)> init_success_callback;
  92. // Whether erase should succeed
  93. std::function<bool(std::uint64_t)> erase_success_callback;
  94. // Whether unlocks should succeed
  95. std::function<bool(std::uint64_t)> unlock_success_callback;
  96. // Whether writes should succeed
  97. std::function<bool(std::uint64_t, std::uint32_t)> write_success_callback;
  98. // Whether locks should succeed
  99. std::function<bool(std::uint64_t)> lock_success_callback;
  100. template <typename... Args>
  101. void append_log(Args&&... args) {
  102. if (write_log.size() < MOCK_WRITE_LOG_MAX_ENTRIES::value) {
  103. write_log.emplace_back(std::forward<Args>(args)...);
  104. }
  105. }
  106. public:
  107. static MockBackingStore& Instance() {
  108. static MockBackingStore instance;
  109. return instance;
  110. }
  111. std::uint64_t erasure_count() const {
  112. return backing_erasure_count;
  113. }
  114. std::uint64_t max_write_count() const {
  115. return backing_max_write_count;
  116. }
  117. std::uint64_t total_write_count() const {
  118. return backing_total_write_count;
  119. }
  120. // The number of times each API was invoked
  121. std::uint64_t init_invoke_count() const {
  122. return backing_init_invoke_count;
  123. }
  124. std::uint64_t unlock_invoke_count() const {
  125. return backing_unlock_invoke_count;
  126. }
  127. std::uint64_t erase_invoke_count() const {
  128. return backing_erase_invoke_count;
  129. }
  130. std::uint64_t write_invoke_count() const {
  131. return backing_write_invoke_count;
  132. }
  133. std::uint64_t lock_invoke_count() const {
  134. return backing_lock_invoke_count;
  135. }
  136. // Clear out the internal data for the next run
  137. void reset_instance();
  138. bool is_locked() const {
  139. return locked;
  140. }
  141. // APIs for the backing store
  142. bool init();
  143. bool unlock();
  144. bool erase();
  145. bool write(std::uint32_t address, backing_store_int_t value);
  146. bool lock();
  147. bool read(std::uint32_t address, backing_store_int_t& value) const;
  148. // Control over when init/writes/erases should succeed
  149. void set_init_callback(std::function<bool(std::uint64_t)> callback) {
  150. init_success_callback = callback;
  151. }
  152. void set_erase_callback(std::function<bool(std::uint64_t)> callback) {
  153. erase_success_callback = callback;
  154. }
  155. void set_unlock_callback(std::function<bool(std::uint64_t)> callback) {
  156. unlock_success_callback = callback;
  157. }
  158. void set_write_callback(std::function<bool(std::uint64_t, std::uint32_t)> callback) {
  159. write_success_callback = callback;
  160. }
  161. void set_lock_callback(std::function<bool(std::uint64_t)> callback) {
  162. lock_success_callback = callback;
  163. }
  164. auto storage_begin() const -> decltype(backing_storage.begin()) {
  165. return backing_storage.begin();
  166. }
  167. auto storage_end() const -> decltype(backing_storage.end()) {
  168. return backing_storage.end();
  169. }
  170. auto storage_begin() -> decltype(backing_storage.begin()) {
  171. return backing_storage.begin();
  172. }
  173. auto storage_end() -> decltype(backing_storage.end()) {
  174. return backing_storage.end();
  175. }
  176. auto log_begin() -> decltype(write_log.begin()) {
  177. return write_log.begin();
  178. }
  179. auto log_end() -> decltype(write_log.end()) {
  180. return write_log.end();
  181. }
  182. auto log_begin() const -> decltype(write_log.begin()) {
  183. return write_log.begin();
  184. }
  185. auto log_end() const -> decltype(write_log.end()) {
  186. return write_log.end();
  187. }
  188. };