General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

254 lines
8.5 KiB

  1. #include "test_scaffold.h"
  2. #include "gp/containers/array.hpp"
  3. #include "gp/containers/vector.hpp"
  4. #include "gp/ipc/envelope/cbor.hpp"
  5. #include "gp/algorithms/tmp_manip.hpp"
  6. #include "gp/functional/monostates.hpp"
  7. #include "gp/utils/allocators/allocator.hpp"
  8. #include <string>
  9. #include <unordered_map>
  10. extern void print_logs();
  11. struct std_allocator : gp::allocator {
  12. using dbg_map = std::unordered_map<void*, size_t>;
  13. [[no_unique_address]] dbg_map debug_info;
  14. /**
  15. * @brief Allocates memory
  16. *
  17. * @param sz the amount of bytes to allocate
  18. *
  19. * @return the allocated memory as a pointer on success
  20. * @return nullptr if it failed allocating
  21. */
  22. virtual void* allocate(size_t sz) {
  23. auto v = new char[sz];
  24. log_segment("data allocated", (std::to_string(sz) + " bytes @"+std::to_string((uintptr_t)v)).c_str());
  25. debug_info[v] = sz;
  26. return v;
  27. }
  28. /**
  29. * @brief Deallocates memory
  30. *
  31. * @param ptr the memory to deallocate
  32. *
  33. * @return true if the memory was successfully deallocated
  34. * @return false if the memory was not deallocated
  35. */
  36. virtual bool deallocate(void* ptr) {
  37. log_segment("data deallocated", "Trying deallocation");
  38. log_segment("data deallocated", ("Target: @" + std::to_string((uintptr_t)ptr)).c_str());
  39. if(!debug_info.contains(ptr)) {
  40. print_logs();
  41. gp_config::assertion(false, "Double free detected");
  42. }
  43. delete (char*)ptr;
  44. log_segment("data deallocated", (std::to_string(debug_info[ptr]) + " bytes @"+std::to_string((uintptr_t)ptr)).c_str());
  45. debug_info.erase(ptr);
  46. return true;
  47. }
  48. /**
  49. * @brief Tries to reallocate memory
  50. *
  51. * @param ptr The memory to reallocate
  52. * @param sz The new size we want to give the memory
  53. *
  54. * @return true if reallocation was successful
  55. * @return false if the reallocation failed
  56. */
  57. virtual bool try_reallocate(void*, size_t) {
  58. return false;
  59. }
  60. virtual ~std_allocator() = default;
  61. };
  62. std_allocator allocator;
  63. enum class co_state {
  64. waiting_receive,
  65. waiting_send,
  66. data_received,
  67. data_sent
  68. };
  69. typedef gp::array<char, 16> identifier_t;
  70. using fd_t = int;
  71. struct packet_info {
  72. uint64_t attempts = 0;
  73. uint64_t sequence = 0;
  74. identifier_t co_id;
  75. gp::vector<char> data{allocator};
  76. };
  77. gp::vector<char>& push_as_cbor(gp::vector<char>& src, identifier_t& value) {
  78. gp::push_as_cbor(src, gp::cbor_tag_initiator{.as_integer = 37});
  79. gp::push_as_cbor(src, value.as_buffer());
  80. return src;
  81. }
  82. gp::vector<char>& push_as_cbor(gp::vector<char>& src, packet_info& value) {
  83. push_as_cbor(src, gp::cbor_tag_initiator{.as_integer = 1994});
  84. push_as_cbor(src, gp::cbor_array_initiator{4});
  85. push_as_cbor(src, value.sequence);
  86. push_as_cbor(src, value.attempts);
  87. push_as_cbor(src, value.co_id);
  88. push_as_cbor(src, value.data.as_buffer());
  89. return src;
  90. }
  91. namespace gp { template<>
  92. gp::pair<gp::optional<packet_info>, parsing_state> read_cbor<packet_info>(parsing_state state, gp::allocator& alloc) {
  93. size_t seq, attempts;
  94. identifier_t uuid;
  95. gp::vector<char> data{alloc};
  96. log_segment("INFO", "Init stage");
  97. bool ok = true;
  98. auto array_parser = [&](parsing_state state, allocator& alloc){
  99. for(size_t idx : {0,1,2,3})
  100. switch(idx) {
  101. case 0:{
  102. log_segment("INFO", "Array stage 0");
  103. auto [v ,new_state] = read_cbor<uint64_t>(state, alloc);
  104. if(v.has_value()) {
  105. seq = v.value();
  106. return new_state;
  107. }
  108. }break;
  109. case 1:{
  110. log_segment("INFO", "Array stage 1");
  111. auto [v ,new_state] = read_cbor<uint64_t>(state, alloc);
  112. if(v.has_value()) {
  113. attempts = v.value();
  114. return new_state;
  115. }
  116. }break;
  117. case 2:{
  118. log_segment("INFO", "Array stage 2");
  119. auto [tg ,nc_state] = read_cbor<cbor_tag_initiator>(state, alloc);
  120. if(!tg.has_value()) break;
  121. if(tg.value().as_integer != 37) break;
  122. log_segment("INFO", "\tGet UUID");
  123. auto [v ,new_state] = read_cbor<gp::vector<char>>(nc_state, alloc);
  124. if(v.has_value()) {
  125. log_segment("INFO", "\tUUID obtained");
  126. for(size_t idx : {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}) {
  127. uuid[idx] = v.value()[idx];
  128. }
  129. return new_state;
  130. }
  131. log_segment("INFO", "\tUUID not found");
  132. }break;
  133. case 3:{
  134. log_segment("INFO", "Array stage 3");
  135. auto [v ,new_state] = read_cbor<gp::vector<char>>(state, alloc);
  136. if(v.has_value()) {
  137. log_segment("INFO", "Data copy");
  138. data = v.value();
  139. log_segment("INFO", "ready to return last stale");
  140. return new_state;
  141. }
  142. }break;
  143. }
  144. ok &= false;
  145. log_segment("ok", ok ? "true" : "false");
  146. return state;
  147. };
  148. parsing_state nc_state = state;
  149. {
  150. log_segment("INFO", "Tag stage");
  151. auto [value, new_state] = read_cbor<cbor_tag_initiator>(nc_state, alloc);
  152. if(!value.has_value()) return {gp::nullopt, state};
  153. nc_state = new_state;
  154. }
  155. {
  156. log_segment("INFO", "Array info stage");
  157. auto new_state = read_cbor_array(nc_state, alloc, array_parser, [&](size_t sz){
  158. ok &= sz == 4;
  159. log_segment("ok", ok ? "true" : "false");
  160. return ok;
  161. });
  162. log_segment("INFO", "Parser returned... Testing");
  163. if(ok && new_state.size() != nc_state.size()) {
  164. log_segment("INFO", "Parsing terminated successfully");
  165. return {packet_info{.attempts = attempts, .sequence = seq, .data = gp::move(data)}, new_state};
  166. }
  167. else{
  168. log_segment("INFO", ("Parsing failed with ok=" + std::string(ok ? "true" : "false")).c_str());
  169. return {nullopt, state};
  170. }
  171. }
  172. }}
  173. struct packet_info_serialization_test : public test_scaffold {
  174. packet_info_serialization_test() {
  175. name = __FILE__ "@packet_info_serialization_test";
  176. }
  177. virtual int run() {
  178. packet_info item;
  179. item.sequence = 1;
  180. item.attempts = 2;
  181. for(auto& c : item.co_id) c = 1;
  182. for(auto idx : {0,1,2,3,4,5,6,7,8,9}) item.data.push_back(idx);
  183. gp::vector<char> serialized(allocator);
  184. push_as_cbor(serialized, item);
  185. log_segment("size", std::to_string(serialized.size()).c_str());
  186. gp_config::assertion(serialized.size() == 36, "serialization of the wrong size");
  187. return 0;
  188. }
  189. };
  190. append_test packet_info_serialization_test_impl(new packet_info_serialization_test());
  191. struct packet_info_deserialization_test : public test_scaffold {
  192. packet_info_deserialization_test() {
  193. name = __FILE__ "@packet_info_deserialization_test";
  194. }
  195. virtual int run() {
  196. packet_info item;
  197. item.sequence = 1;
  198. item.attempts = 2;
  199. for(auto& c : item.co_id) c = 1;
  200. for(auto idx : {0,1,2,3,4,5,6,7,8,9}) item.data.push_back(idx);
  201. gp::vector<char> serialized(allocator);
  202. log_segment("INFO", "Serialization init");
  203. push_as_cbor(serialized, item);
  204. log_segment("INFO", "Item serialized");
  205. log_segment("size", std::to_string(serialized.size()).c_str());
  206. gp_config::assertion(serialized.size() == 36, "serialization of the wrong size");
  207. log_segment("INFO", "Item controlled");
  208. auto [value, state] = gp::read_cbor<packet_info>(serialized.as_buffer(), allocator);
  209. gp_config::assertion(value.has_value(), "deserialization failed");
  210. gp_config::assertion(!state.size(), "unprocessed state remains");
  211. gp_config::assertion(value.value().sequence == item.sequence, "comparison failed step 1");
  212. gp_config::assertion(value.value().attempts == item.attempts, "comparison failed step 2");
  213. gp_config::assertion(value.value().co_id == item.co_id, "comparison failed step 3");
  214. gp_config::assertion(value.value().data == item.data, "comparison failed step 4");
  215. return 0;
  216. }
  217. };
  218. append_test packet_info_deserialization_test_impl(new packet_info_deserialization_test());