03-slip.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include "limbo/errc.h"
  2. #include "limbo/slip/escape.hpp"
  3. #include "limbo/slip/state.hpp"
  4. #include "test-utils.h"
  5. using namespace limbo;
  6. using State = slip::State<void>;
  7. using Context = typename State::Context;
  8. using Packet = typename State::Packet;
  9. TEST_CASE("offsets in unescaping", "[slip]") {
  10. auto state = State();
  11. SECTION("normal in") {
  12. unsigned char buff_raw[] = {'a'};
  13. auto buff = Chunk(buff_raw, sizeof(buff_raw));
  14. auto r = slip::unescape(buff, &state);
  15. REQUIRE(!r);
  16. CHECK(r.state() == &state);
  17. CHECK(r.error_code() == (uint32_t)Errc::slip_incomplete);
  18. CHECK(state.position == 1);
  19. CHECK(state.offset == 0);
  20. }
  21. SECTION("just esc in") {
  22. unsigned char buff_raw[] = {0xDB};
  23. auto buff = Chunk(buff_raw, sizeof(buff_raw));
  24. auto r = slip::unescape(buff, &state);
  25. REQUIRE(!r);
  26. CHECK(r.state() == &state);
  27. CHECK(r.error_code() == (uint32_t)Errc::slip_incomplete);
  28. CHECK(state.position == 0);
  29. CHECK(state.offset == 1);
  30. }
  31. SECTION("just esc + esc_end in") {
  32. unsigned char buff_raw[] = {0xDB, 0xDD};
  33. auto buff = Chunk(buff_raw, 1);
  34. auto r = slip::unescape(buff, &state);
  35. REQUIRE(!r);
  36. CHECK(r.state() == &state);
  37. CHECK(r.error_code() == (uint32_t)Errc::slip_incomplete);
  38. CHECK(state.position == 0);
  39. CHECK(state.offset == 1);
  40. buff = Chunk(buff_raw, 2);
  41. r = slip::unescape(buff, &state);
  42. REQUIRE(!r);
  43. CHECK(r.state() == &state);
  44. CHECK(r.error_code() == (uint32_t)Errc::slip_incomplete);
  45. CHECK(state.position == 1);
  46. CHECK(state.offset == 0);
  47. }
  48. }
  49. TEST_CASE("by-byte parsing", "[slip]") {
  50. auto state = State();
  51. unsigned char payload_raw[] = {0xC0, 'a', 'b', 0xDB, 0xDB, 'c', 0xC0};
  52. unsigned char input_buff_raw[50];
  53. auto payload = Chunk(payload_raw, sizeof(payload_raw));
  54. auto input_buff = Chunk(input_buff_raw, sizeof(input_buff_raw));
  55. auto result = slip::escape(input_buff, payload, &state);
  56. REQUIRE(result);
  57. REQUIRE(!result.demand());
  58. auto input_escaped = result.consumed();
  59. unsigned char output_buff_raw[50];
  60. auto o = output_buff_raw;
  61. auto i = input_buff_raw;
  62. for (uint32_t c = 0; c < input_escaped.size(); c++) {
  63. o[state.position + state.offset] = *i++;
  64. auto ptr = output_buff_raw + state.position;
  65. auto sub_buff = Chunk(ptr, state.offset + 1);
  66. auto r = slip::unescape(sub_buff, &state);
  67. if (!r) {
  68. REQUIRE(r.error_code() == (uint32_t)Errc::slip_incomplete);
  69. } else {
  70. CHECK(state.get_parsed().payload == payload);
  71. CHECK(state.position == 0);
  72. CHECK(state.offset == 0);
  73. break;
  74. }
  75. }
  76. }
  77. TEST_CASE("escaping", "[slip]") {
  78. auto state = State();
  79. SECTION("fully avaialable") {
  80. SECTION("simple") {
  81. unsigned char sample_raw[] = {'a', 'b', 'c', 0, 0xC0};
  82. unsigned char buff_raw[] = {'a', 'b', 'c', 0, 0};
  83. unsigned char buff_orig_raw[] = {'a', 'b', 'c', 0, 0};
  84. auto buff = Chunk(buff_raw, sizeof(buff_raw));
  85. auto data = Chunk(buff_raw, sizeof(buff_raw) - 1);
  86. auto data_orig = Chunk(buff_orig_raw, data.size());
  87. auto sample = Chunk(sample_raw, sizeof(buff_raw));
  88. auto result = slip::escape(buff, data, &state);
  89. REQUIRE(result);
  90. CHECK(buff == sample);
  91. CHECK(result.consumed() == sample);
  92. auto unescaped = slip::unescape(buff, &state);
  93. REQUIRE(unescaped);
  94. CHECK(unescaped.state() == &state);
  95. CHECK(unescaped.consumed() == buff);
  96. CHECK(state.packet.payload == data_orig);
  97. CHECK(state.position == 0);
  98. }
  99. SECTION("payload with sequences to be escaped") {
  100. unsigned char sample_raw[] = {0xDB, 0xDC, 0xDB, 0xDD, 'a',
  101. 'b', 'c', 0, 0xC0};
  102. unsigned char buff_raw[] = {0xC0, 0xDB, 'a', 'b', 'c', 0, 0, 0, 0};
  103. unsigned char buff_orig_raw[] = {0xC0, 0xDB, 'a', 'b', 'c', 0, 0, 0, 0};
  104. auto buff = Chunk(buff_raw, sizeof(buff_raw));
  105. static_assert(sizeof(buff_raw) == sizeof(sample_raw));
  106. assert(sizeof(sample_raw) == 9);
  107. assert(buff.size() == 9);
  108. auto data = Chunk(buff_raw, 6);
  109. auto data_orig = Chunk(buff_orig_raw, data.size());
  110. auto sample = Chunk(sample_raw, sizeof(buff_raw));
  111. auto result = slip::escape(buff, data, &state);
  112. REQUIRE(result);
  113. CHECK(buff == sample);
  114. CHECK(result.consumed() == sample);
  115. auto unescaped = slip::unescape(buff, &state);
  116. REQUIRE(unescaped);
  117. CHECK(unescaped.state() == &state);
  118. CHECK(unescaped.consumed() == buff);
  119. CHECK(state.packet.payload == data_orig);
  120. CHECK(state.position == 0);
  121. }
  122. SECTION("payload outside of buff") {
  123. unsigned char sample_raw[] = {'a', 'b', 'c', 0, 0xC0};
  124. unsigned char buff_raw[] = {0, 0, 0, 0, 0};
  125. unsigned char buff_orig_raw[] = {'a', 'b', 'c', 0, 0};
  126. auto buff = Chunk(buff_raw, sizeof(buff_raw));
  127. auto data = Chunk(buff_orig_raw, sizeof(buff_orig_raw) - 1);
  128. auto data_orig = Chunk(buff_orig_raw, data.size());
  129. auto sample = Chunk(sample_raw, sizeof(buff_raw));
  130. auto result = slip::escape(buff, data, &state);
  131. REQUIRE(result);
  132. CHECK(buff == sample);
  133. CHECK(result.consumed() == sample);
  134. auto unescaped = slip::unescape(buff, &state);
  135. REQUIRE(unescaped);
  136. CHECK(unescaped.state() == &state);
  137. CHECK(unescaped.consumed() == buff);
  138. CHECK(state.packet.payload == data_orig);
  139. CHECK(state.position == 0);
  140. }
  141. }
  142. SECTION("partially available") {
  143. unsigned char sample_raw[] = {0xC0, 'a', 'b', 'c', 0xC0};
  144. unsigned char buff_raw[50];
  145. auto buff = Chunk(buff_raw, sizeof(buff_raw));
  146. auto data = Chunk(sample_raw, sizeof(sample_raw));
  147. auto result = slip::escape(buff, data, &state);
  148. REQUIRE(result);
  149. auto consumed = result.consumed();
  150. auto sz = consumed.size();
  151. uint32_t i = 0;
  152. while (true) {
  153. auto sub_buff = Chunk(buff_raw, i);
  154. auto r = slip::unescape(sub_buff, &state);
  155. if (!r) {
  156. REQUIRE(r.error_code() == (uint32_t)Errc::slip_incomplete);
  157. auto delta = r.consumed().size() - state.position;
  158. if (delta) {
  159. auto o = buff_raw + state.position;
  160. auto s = o + delta;
  161. while (s < buff.data() + buff.size()) {
  162. *o++ = *s++;
  163. }
  164. sz -= delta;
  165. } else {
  166. ++i;
  167. }
  168. } else {
  169. CHECK(state.get_parsed().payload == data);
  170. CHECK(state.position == 0);
  171. REQUIRE(r.consumed().size() == data.size() + 1);
  172. break;
  173. }
  174. }
  175. }
  176. }
  177. uint8_t example_raw[] = {'H', 'e', 'l', 'l', 'o', 0xC0};
  178. auto example_chunk = Chunk(example_raw, sizeof(example_raw));
  179. uint8_t payload[] = {'H', 'e', 'l', 'l', 'o'};
  180. auto payload_chunk = Chunk(payload, sizeof(payload));
  181. TEST_CASE("send", "[slip]") {
  182. char buff[sizeof(example_raw)];
  183. auto buff_chunk = Chunk(buff, sizeof(example_raw));
  184. auto ctx = Context{};
  185. auto state = State();
  186. SECTION("no enough space") {
  187. auto zero_chunk = Chunk(buff, 0);
  188. auto result = Packet::send(state, ctx, zero_chunk, payload_chunk);
  189. REQUIRE(!result);
  190. CHECK(result.state() == &state);
  191. CHECK(result.error_code() == (uint32_t)Errc::no_enough_space);
  192. }
  193. auto result = Packet::send(state, ctx, buff_chunk, payload_chunk);
  194. REQUIRE(result);
  195. auto res_buff = result.consumed();
  196. CHECK((void *)res_buff.data() == (void *)buff);
  197. CHECK(res_buff.size() == example_chunk.size());
  198. CHECK(res_buff == example_chunk);
  199. }
  200. TEST_CASE("recv/success", "[slip]") {
  201. auto state = State();
  202. auto result = state.recv(example_chunk, nullptr);
  203. CHECK(result);
  204. CHECK(result.consumed() == example_chunk);
  205. CHECK(result.state() == &state);
  206. auto &packet = state.get_parsed();
  207. CHECK(packet.payload == payload_chunk);
  208. }
  209. TEST_CASE("recv empty block /success", "[slip]") {
  210. uint8_t example_raw[] = {0xC0};
  211. auto example_chunk = Chunk(example_raw, sizeof(example_raw));
  212. auto state = State();
  213. auto result = state.recv(example_chunk, nullptr);
  214. CHECK(result);
  215. CHECK(result.consumed() == example_chunk);
  216. CHECK(result.state() == &state);
  217. auto &packet = state.get_parsed();
  218. CHECK(packet.payload.size() == 0);
  219. }