#include "test_scaffold.h" #include "gp/containers/array.hpp" #include "gp/containers/vector.hpp" #include "gp/ipc/envelope/cbor.hpp" #include "gp/algorithms/tmp_manip.hpp" #include "gp/functional/monostates.hpp" #include "gp/utils/allocators/allocator.hpp" #include #include extern void print_logs(); struct std_allocator : gp::allocator { using dbg_map = std::unordered_map; [[no_unique_address]] dbg_map debug_info; /** * @brief Allocates memory * * @param sz the amount of bytes to allocate * * @return the allocated memory as a pointer on success * @return nullptr if it failed allocating */ virtual void* allocate(size_t sz) { auto v = new char[sz]; log_segment("data allocated", (std::to_string(sz) + " bytes @"+std::to_string((uintptr_t)v)).c_str()); debug_info[v] = sz; return v; } /** * @brief Deallocates memory * * @param ptr the memory to deallocate * * @return true if the memory was successfully deallocated * @return false if the memory was not deallocated */ virtual bool deallocate(void* ptr) { log_segment("data deallocated", "Trying deallocation"); log_segment("data deallocated", ("Target: @" + std::to_string((uintptr_t)ptr)).c_str()); if(!debug_info.contains(ptr)) { print_logs(); gp_config::assertion(false, "Double free detected"); } delete (char*)ptr; log_segment("data deallocated", (std::to_string(debug_info[ptr]) + " bytes @"+std::to_string((uintptr_t)ptr)).c_str()); debug_info.erase(ptr); return true; } /** * @brief Tries to reallocate memory * * @param ptr The memory to reallocate * @param sz The new size we want to give the memory * * @return true if reallocation was successful * @return false if the reallocation failed */ virtual bool try_reallocate(void*, size_t) { return false; } virtual ~std_allocator() = default; }; std_allocator allocator; enum class co_state { waiting_receive, waiting_send, data_received, data_sent }; typedef gp::array identifier_t; using fd_t = int; struct packet_info { uint64_t attempts = 0; uint64_t sequence = 0; identifier_t co_id; gp::vector data{allocator}; }; gp::vector& push_as_cbor(gp::vector& src, identifier_t& value) { gp::push_as_cbor(src, gp::cbor_tag_initiator{.as_integer = 37}); gp::push_as_cbor(src, value.as_buffer()); return src; } gp::vector& push_as_cbor(gp::vector& src, packet_info& value) { push_as_cbor(src, gp::cbor_tag_initiator{.as_integer = 1994}); push_as_cbor(src, gp::cbor_array_initiator{4}); push_as_cbor(src, value.sequence); push_as_cbor(src, value.attempts); push_as_cbor(src, value.co_id); push_as_cbor(src, value.data.as_buffer()); return src; } namespace gp { template<> gp::pair, parsing_state> read_cbor(parsing_state state, gp::allocator& alloc) { size_t seq, attempts; identifier_t uuid; gp::vector data{alloc}; log_segment("INFO", "Init stage"); bool ok = true; auto array_parser = [&](parsing_state state, allocator& alloc){ for(size_t idx : {0,1,2,3}) switch(idx) { case 0:{ log_segment("INFO", "Array stage 0"); auto [v ,new_state] = read_cbor(state, alloc); if(v.has_value()) { seq = v.value(); return new_state; } }break; case 1:{ log_segment("INFO", "Array stage 1"); auto [v ,new_state] = read_cbor(state, alloc); if(v.has_value()) { attempts = v.value(); return new_state; } }break; case 2:{ log_segment("INFO", "Array stage 2"); auto [tg ,nc_state] = read_cbor(state, alloc); if(!tg.has_value()) break; if(tg.value().as_integer != 37) break; log_segment("INFO", "\tGet UUID"); auto [v ,new_state] = read_cbor>(nc_state, alloc); if(v.has_value()) { log_segment("INFO", "\tUUID obtained"); for(size_t idx : {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}) { uuid[idx] = v.value()[idx]; } return new_state; } log_segment("INFO", "\tUUID not found"); }break; case 3:{ log_segment("INFO", "Array stage 3"); auto [v ,new_state] = read_cbor>(state, alloc); if(v.has_value()) { log_segment("INFO", "Data copy"); data = v.value(); log_segment("INFO", "ready to return last stale"); return new_state; } }break; } ok &= false; log_segment("ok", ok ? "true" : "false"); return state; }; parsing_state nc_state = state; { log_segment("INFO", "Tag stage"); auto [value, new_state] = read_cbor(nc_state, alloc); if(!value.has_value()) return {gp::nullopt, state}; nc_state = new_state; } { log_segment("INFO", "Array info stage"); auto new_state = read_cbor_array(nc_state, alloc, array_parser, [&](size_t sz){ ok &= sz == 4; log_segment("ok", ok ? "true" : "false"); return ok; }); log_segment("INFO", "Parser returned... Testing"); if(ok && new_state.size() != nc_state.size()) { log_segment("INFO", "Parsing terminated successfully"); return {packet_info{.attempts = attempts, .sequence = seq, .data = gp::move(data)}, new_state}; } else{ log_segment("INFO", ("Parsing failed with ok=" + std::string(ok ? "true" : "false")).c_str()); return {nullopt, state}; } } }} struct packet_info_serialization_test : public test_scaffold { packet_info_serialization_test() { name = __FILE__ "@packet_info_serialization_test"; } virtual int run() { packet_info item; item.sequence = 1; item.attempts = 2; for(auto& c : item.co_id) c = 1; for(auto idx : {0,1,2,3,4,5,6,7,8,9}) item.data.push_back(idx); gp::vector serialized(allocator); push_as_cbor(serialized, item); log_segment("size", std::to_string(serialized.size()).c_str()); gp_config::assertion(serialized.size() == 36, "serialization of the wrong size"); return 0; } }; append_test packet_info_serialization_test_impl(new packet_info_serialization_test()); struct packet_info_deserialization_test : public test_scaffold { packet_info_deserialization_test() { name = __FILE__ "@packet_info_deserialization_test"; } virtual int run() { packet_info item; item.sequence = 1; item.attempts = 2; for(auto& c : item.co_id) c = 1; for(auto idx : {0,1,2,3,4,5,6,7,8,9}) item.data.push_back(idx); gp::vector serialized(allocator); log_segment("INFO", "Serialization init"); push_as_cbor(serialized, item); log_segment("INFO", "Item serialized"); log_segment("size", std::to_string(serialized.size()).c_str()); gp_config::assertion(serialized.size() == 36, "serialization of the wrong size"); log_segment("INFO", "Item controlled"); auto [value, state] = gp::read_cbor(serialized.as_buffer(), allocator); gp_config::assertion(value.has_value(), "deserialization failed"); gp_config::assertion(!state.size(), "unprocessed state remains"); gp_config::assertion(value.value().sequence == item.sequence, "comparison failed step 1"); gp_config::assertion(value.value().attempts == item.attempts, "comparison failed step 2"); gp_config::assertion(value.value().co_id == item.co_id, "comparison failed step 3"); gp_config::assertion(value.value().data == item.data, "comparison failed step 4"); return 0; } }; append_test packet_info_deserialization_test_impl(new packet_info_deserialization_test());