From 37359e3acc01802b679f83d642cb7232fb8de60e Mon Sep 17 00:00:00 2001 From: Marcelo Zimbres Date: Wed, 30 Dec 2020 13:53:56 +0100 Subject: [PATCH] Changes: - Using string_view in the interface. - Improvements in the accumulator. - Renames class. - Reverts unwanted changes to an example. - One test function for each of the redis data types. --- Makefile | 2 +- examples/async_events.cpp | 2 +- examples/async_pubsub.cpp | 2 +- examples/sync_basic.cpp | 7 +- examples/sync_events.cpp | 2 +- include/aedis/pipeline.hpp | 474 +++++++++++++++++++++++++------------ include/aedis/response.hpp | 5 +- tests/general.cpp | 173 ++++++++++---- 8 files changed, 459 insertions(+), 208 deletions(-) diff --git a/Makefile b/Makefile index 74d3bb12..155b8feb 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ examples += sync_responses examples += sync_events examples += async_basic examples += async_reconnect -examples += async_own_struct +#examples += async_own_struct examples += async_all_hashes examples += async_responses examples += async_events diff --git a/examples/async_events.cpp b/examples/async_events.cpp index 95a48fdb..7b0e5352 100644 --- a/examples/async_events.cpp +++ b/examples/async_events.cpp @@ -40,7 +40,7 @@ net::awaitable example() std::string buffer; for (;;) { - switch (p.events.front()) { + switch (p.events.front().second) { case myevents::list: { resp::response_list res; diff --git a/examples/async_pubsub.cpp b/examples/async_pubsub.cpp index 7e8c7959..6e5b4306 100644 --- a/examples/async_pubsub.cpp +++ b/examples/async_pubsub.cpp @@ -64,7 +64,7 @@ net::awaitable subscriber() // Reads published messages. for (;;) { - resp::response_publish res; + resp::response_static_array res; co_await resp::async_read(socket, buffer, res); print(res.result); } diff --git a/examples/sync_basic.cpp b/examples/sync_basic.cpp index fff61011..eef22440 100644 --- a/examples/sync_basic.cpp +++ b/examples/sync_basic.cpp @@ -16,7 +16,8 @@ int main() { try { resp::pipeline p; - p.subscribe("channel"); + p.set("Password", {"12345"}); + p.quit(); io_context ioc {1}; tcp::resolver resv(ioc); @@ -26,9 +27,9 @@ int main() std::string buffer; for (;;) { - resp::response_array res; + resp::response_simple_string res; resp::read(socket, buffer, res); - print(res.result); + std::cout << res.result << std::endl; } } catch (std::exception const& e) { std::cerr << e.what() << std::endl; diff --git a/examples/sync_events.cpp b/examples/sync_events.cpp index 52026a66..e11cb97c 100644 --- a/examples/sync_events.cpp +++ b/examples/sync_events.cpp @@ -36,7 +36,7 @@ int main() std::string buffer; for (;;) { - switch (p.events.front()) { + switch (p.events.front().second) { case myevents::list: { resp::response_list res; diff --git a/include/aedis/pipeline.hpp b/include/aedis/pipeline.hpp index b3ddcf71..73bc67d3 100644 --- a/include/aedis/pipeline.hpp +++ b/include/aedis/pipeline.hpp @@ -19,7 +19,7 @@ namespace aedis { namespace resp { inline -void make_bulky_item(std::string& to, std::string const& param) +void make_bulk(std::string& to, std::string_view param) { to += "$"; to += std::to_string(std::size(param)); @@ -37,44 +37,62 @@ void make_header(std::string& to, int size) } struct accumulator { - auto operator()(std::string a, std::string b) const + auto + operator()( + std::string a, + std::string_view b) const { - make_bulky_item(a, b); + make_bulk(a, b); return a; } - auto operator()(std::string a, int b) const + template + auto + operator()( + std::string a, + T b, + std::enable_if<(std::is_integral::value || std::is_floating_point::value), + bool>::type = false) const { - make_bulky_item(a, std::to_string(b)); + make_bulk(a, std::to_string(b)); return a; } - auto operator()(std::string a, std::pair b) const + auto + operator()( + std::string a, + std::pair b) const { - make_bulky_item(a, b.first); - make_bulky_item(a, b.second); + make_bulk(a, b.first); + make_bulk(a, b.second); return a; } - auto operator()(std::string a, std::pair b) const + template + auto + operator()( + std::string a, + std::pair b, + std::enable_if<(std::is_integral::value || std::is_floating_point::value), + bool>::type = false) const { - make_bulky_item(a, std::to_string(b.first)); - make_bulky_item(a, b.second); + make_bulk(a, std::to_string(b.first)); + make_bulk(a, b.second); return a; } }; inline -void assemble(std::string& ret, char const* cmd) +void assemble(std::string& ret, std::string_view cmd) { make_header(ret, 1); - make_bulky_item(ret, cmd); + make_bulk(ret, cmd); } template auto assemble( std::string& ret - , char const* cmd - , std::initializer_list key + , std::string_view cmd + , std::initializer_list key , Iter begin , Iter end , int size = 1) @@ -89,7 +107,7 @@ auto assemble( std::string& ret // functions below instead of declaring a below. std::string a; make_header(a, 1 + d1 + size * d2); - make_bulky_item(a, cmd); + make_bulk(a, cmd); auto b = std::accumulate( std::cbegin(key) @@ -105,130 +123,212 @@ auto assemble( std::string& ret } inline -void assemble(std::string& ret, char const* cmd, std::string const& key) +void assemble(std::string& ret, std::string_view cmd, std::string_view key) { - std::initializer_list dummy; + std::initializer_list dummy; assemble(ret, cmd, {key}, std::cbegin(dummy), std::cend(dummy)); } -enum class command {ignore}; +enum class command +{ append +, auth +, bgrewriteaof +, bgsave +, bitcount +, del +, exec +, expire +, flushall +, get +, hello +, hget +, hgetall +, hincrby +, hkeys +, hlen +, hmget +, hset +, hvals +, incr +, keys +, llen +, lpop +, lpush +, lrange +, ltrim +, multi +, ping +, psubscribe +, publish +, quit +, role +, rpush +, sadd +, scard +, sentinel +, set +, smembers +, subscribe +, unsubscribe +, zadd +, zrange +, zrangebyscore +, zremrangebyscore +}; -template +enum class event {ignore}; + +template struct pipeline { std::string payload; - std::queue events; + std::queue> events; public: void ping(Event e = Event::ignore) { resp::assemble(payload, "PING"); - events.push(e); + events.push({command::ping, e}); } void quit(Event e = Event::ignore) { resp::assemble(payload, "QUIT"); - events.push(e); + events.push({command::quit, e}); } void multi(Event e = Event::ignore) { resp::assemble(payload, "MULTI"); - events.push(e); + events.push({command::multi, e}); } void exec(Event e = Event::ignore) { resp::assemble(payload, "EXEC"); - events.push(e); + events.push({command::exec, e}); } - void incr(std::string const& key, Event e = Event::ignore) + void incr(std::string_view key, Event e = Event::ignore) { resp::assemble(payload, "INCR", key); - events.push(e); + events.push({command::incr, e}); } - auto auth(std::string const& pwd, Event e = Event::ignore) + void + auth( + std::string_view pwd, + Event e = Event::ignore) { resp::assemble(payload, "AUTH", pwd); - events.push(e); + events.push({command::auth, e}); } auto bgrewriteaof(Event e = Event::ignore) { resp::assemble(payload, "BGREWRITEAOF"); - events.push(e); + events.push({command::bgrewriteaof, e}); } auto role(Event e = Event::ignore) { resp::assemble(payload, "ROLE"); - events.push(e); + events.push({command::role, e}); } auto bgsave(Event e = Event::ignore) { resp::assemble(payload, "BGSAVE"); + events.push({command::bgsave, e}); } auto flushall(Event e = Event::ignore) { resp::assemble(payload, "FLUSHALL"); - events.push(e); + events.push({command::flushall, e}); } - auto lpop(std::string const& key, Event e = Event::ignore) + void + lpop( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "LPOP", key); - events.push(e); + events.push({command::lpop, e}); } - auto subscribe(std::string const& key, Event e = Event::ignore) + void + subscribe( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "SUBSCRIBE", key); - events.push(e); + events.push({command::subscribe, e}); } - auto unsubscribe(std::string const& key, Event e = Event::ignore) + void + unsubscribe( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "UNSUBSCRIBE", key); - events.push(e); + events.push({command::unsubscribe, e}); } - auto get(std::string const& key, Event e = Event::ignore) + void + get( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "GET", key); - events.push(e); + events.push({command::get, e}); } - auto keys(std::string const& pattern, Event e = Event::ignore) + void + keys( + std::string_view pattern, + Event e = Event::ignore) { resp::assemble(payload, "KEYS", pattern); - events.push(e); + events.push({command::keys, e}); } - void hello(std::string const& key, Event e = Event::ignore) + void + hello( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "HELLO", key); - events.push(e); + events.push({command::hello, e}); } - auto sentinel(std::string const& arg, std::string const& name, Event e = Event::ignore) + void + sentinel( + std::string_view arg, + std::string_view name, + Event e = Event::ignore) { auto par = {name}; resp::assemble(payload, "SENTINEL", {arg}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::sentinel, e}); } - auto append(std::string const& key, std::string const& msg, Event e = Event::ignore) + auto + append( + std::string_view key, + std::string_view msg, + Event e = Event::ignore) { auto par = {msg}; resp::assemble(payload, "APPEND", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::append, e}); } - auto bitcount(std::string const& key, int start = 0, int end = -1, Event e = Event::ignore) + auto + bitcount( + std::string_view key, + int start = 0, + int end = -1, + Event e = Event::ignore) { auto par = {std::to_string(start), std::to_string(end)}; resp::assemble( payload @@ -236,24 +336,36 @@ public: , {key} , std::cbegin(par) , std::cend(par)); - events.push(e); + events.push({command::bitcount, e}); } template - auto rpush(std::string const& key, Iter begin, Iter end, Event e = Event::ignore) + auto + rpush( + std::string_view key, + Iter begin, + Iter end, + Event e = Event::ignore) { resp::assemble(payload, "RPUSH", {key}, begin, end); - events.push(e); + events.push({command::rpush, e}); } template - auto rpush(std::string const& key, std::initializer_list v, Event e = Event::ignore) + auto + rpush( + std::string_view key, + std::initializer_list v, + Event e = Event::ignore) { return rpush(key, std::cbegin(v), std::cend(v), e); } template - void rpush(std::string const& key, Range const& v, Event e = Event::ignore) + void + rpush( + std::string_view key, + Range const& v, Event e = Event::ignore) { using std::cbegin; using std::cend; @@ -261,154 +373,185 @@ public: } template - auto lpush(std::string const& key, Iter begin, Iter end, Event e = Event::ignore) + auto + lpush( + std::string_view key, + Iter begin, + Iter end, + Event e = Event::ignore) { resp::assemble(payload, "LPUSH", {key}, begin, end); - events.push(e); - } - - auto psubscribe(std::initializer_list l, Event e = Event::ignore) - { - std::initializer_list dummy = {}; - resp::assemble(payload, "PSUBSCRIBE", l, std::cbegin(dummy), std::cend(dummy)); - events.push(e); - } - - auto publish(std::string const& key, std::string const& msg, Event e = Event::ignore) - { - auto par = {msg}; - resp::assemble(payload, "PUBLISH", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::lpush, e}); } auto - set(std::string const& key, - std::initializer_list args, + psubscribe( + std::initializer_list l, + Event e = Event::ignore) + { + std::initializer_list dummy = {}; + resp::assemble(payload, "PSUBSCRIBE", l, std::cbegin(dummy), std::cend(dummy)); + events.push({command::psubscribe, e}); + } + + auto + publish( + std::string_view key, + std::string_view msg, + Event e = Event::ignore) + { + auto par = {msg}; + resp::assemble(payload, "PUBLISH", {key}, std::cbegin(par), std::cend(par)); + events.push({command::publish, e}); + } + + auto + set(std::string_view key, + std::initializer_list args, Event e = Event::ignore) { resp::assemble(payload, "SET", {key}, std::cbegin(args), std::cend(args)); + events.push({command::set, e}); } - //auto - //hset(std::string const& key, - // std::initializer_list l, - // Event e = Event::ignore) - //{ - // resp::assemble(payload, "HSET", {key}, std::cbegin(l), std::cend(l)); - // events.push(e); - //} - // TODO: Find a way to assert the value type is a pair. template auto - hset(std::string const& key, Range const& r, Event e = Event::ignore) + hset( + std::string_view key, + Range const& r, Event e = Event::ignore) { using std::cbegin; using std::cend; resp::assemble(payload, "HSET", {key}, std::cbegin(r), std::cend(r), 2); - events.push(e); + events.push({command::hset, e}); } auto - hincrby(std::string const& key, - std::string const& field, - int by, - Event e = Event::ignore) + hincrby( + std::string_view key, + std::string_view field, + int by, + Event e = Event::ignore) { auto par = {field, std::to_string(by)}; resp::assemble(payload, "HINCRBY", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::hincrby, e}); } auto - hkeys(std::string const& key, Event e = Event::ignore) + hkeys( + std::string_view key, + Event e = Event::ignore) { auto par = {""}; resp::assemble(payload, "HKEYS", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::hkeys, e}); } - auto hlen(std::string const& key, Event e = Event::ignore) + auto + hlen( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "HLEN", {key}); - events.push(e); + events.push({command::hlen, e}); } - auto hgetall(std::string const& key, Event e = Event::ignore) + auto + hgetall( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "HGETALL", {key}); - events.push(e); + events.push({command::hgetall, e}); } - auto hvals(std::string const& key, Event e = Event::ignore) + auto + hvals( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "HVALS", {key}); - events.push(e); + events.push({command::hvals, e}); } - auto hget(std::string const& key, std::string const& field, Event e = Event::ignore) + auto + hget( + std::string_view key, + std::string_view field, + Event e = Event::ignore) { auto par = {field}; resp::assemble(payload, "HGET", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::hget, e}); } auto - hmget(std::string const& key, - std::initializer_list fields, - Event e = Event::ignore) + hmget( + std::string_view key, + std::initializer_list fields, + Event e = Event::ignore) { resp::assemble( payload - , "HMGET" - , {key} - , std::cbegin(fields) - , std::cend(fields)); - events.push(e); + , "HMGET" + , {key} + , std::cbegin(fields) + , std::cend(fields)); + + events.push({command::hmget, e}); } - auto expire(std::string const& key, int secs, Event e = Event::ignore) + auto + expire( + std::string_view key, + int secs, + Event e = Event::ignore) { auto par = {std::to_string(secs)}; resp::assemble(payload, "EXPIRE", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::expire, e}); } auto - zadd(std::string const& key, - int score, std::string const& value, - Event e = Event::ignore) + zadd( + std::string_view key, + int score, + std::string_view value, + Event e = Event::ignore) { auto par = {std::to_string(score), value}; resp::assemble(payload, "ZADD", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::zadd, e}); } template auto - zadd(std::initializer_list key, + zadd(std::initializer_list key, Range const& r, Event e = Event::ignore) { resp::assemble(payload, "ZADD", key, std::cbegin(r), std::cend(r), 2); - events.push(e); + events.push({command::zadd, e}); } auto - zrange(std::string const& key, + zrange(std::string_view key, int min = 0, int max = -1, Event e = Event::ignore) { auto par = {std::to_string(min), std::to_string(max)}; resp::assemble(payload, "ZRANGE", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::zrange, e}); } auto - zrangebyscore(std::string const& key, - int min, - int max, - Event e = Event::ignore) + zrangebyscore( + std::string_view key, + int min, + int max, + Event e = Event::ignore) { auto max_str = std::string {"inf"}; if (max != -1) @@ -416,76 +559,113 @@ public: auto par = {std::to_string(min) , max_str}; resp::assemble(payload, "ZRANGEBYSCORE", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::zrangebyscore, e}); } - auto zremrangebyscore(std::string const& key, int score) + auto + zremrangebyscore( + std::string_view key, + int score, + Event e = Event::ignore) { auto const s = std::to_string(score); auto par = {s, s}; resp::assemble(payload, "ZREMRANGEBYSCORE", {key}, std::cbegin(par), std::cend(par)); + events.push({command::zremrangebyscore, e}); } - auto lrange(std::string const& key, int min = 0, int max = -1, Event e = Event::ignore) + auto + lrange( + std::string_view key, + int min = 0, + int max = -1, + Event e = Event::ignore) { - auto par = { std::to_string(min) , std::to_string(max) }; + auto par = {std::to_string(min), std::to_string(max)}; resp::assemble(payload, "LRANGE", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::lrange, e}); } - auto ltrim(std::string const& key, int min = 0, int max = -1, Event e = Event::ignore) + auto + ltrim( + std::string_view key, + int min = 0, + int max = -1, + Event e = Event::ignore) { - auto par = { std::to_string(min) , std::to_string(max) }; + auto par = {std::to_string(min), std::to_string(max)}; resp::assemble(payload, "LTRIM", {key}, std::cbegin(par), std::cend(par)); - events.push(e); + events.push({command::ltrim, e}); } - auto del(std::string const& key, Event e = Event::ignore) + auto + del( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "DEL", key); - events.push(e); + events.push({command::del, e}); } - auto llen(std::string const& key, Event e = Event::ignore) + auto + llen( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "LLEN", key); - events.push(e); + events.push({command::llen, e}); } template - void sadd(std::string const& key, Iter begin, Iter end, Event e = Event::ignore) + void + sadd( + std::string_view key, + Iter begin, + Iter end, + Event e = Event::ignore) { resp::assemble(payload, "SADD", {key}, begin, end); - events.push(e); + events.push({command::sadd, e}); } template - void sadd(std::string const& key, Range const& r, Event e = Event::ignore) + void + sadd( + std::string_view key, + Range const& r, + Event e = Event::ignore) { using std::cbegin; using std::cend; sadd(key, cbegin(r), cend(r), e); } - auto smembers(std::string const& key, Event e = Event::ignore) + auto + smembers( + std::string_view key, + Event e = Event::ignore) { resp::assemble(payload, "SMEMBERS", key); - events.push(e); - } - - auto scard(std::string const& key, Event e = Event::ignore) - { - resp::assemble(payload, "SCARD", key); - events.push(e); + events.push({command::smembers, e}); } auto - scard(std::string const& key, - std::initializer_list l, - Event e = Event::ignore) + scard( + std::string_view key, + Event e = Event::ignore) + { + resp::assemble(payload, "SCARD", key); + events.push({command::scard, e}); + } + + auto + scard( + std::string_view key, + std::initializer_list l, + Event e = Event::ignore) { resp::assemble(payload, "SDIFF", {key}, std::cbegin(l), std::cend(l)); - events.push(e); + events.push({command::scard, e}); } }; diff --git a/include/aedis/response.hpp b/include/aedis/response.hpp index 895f7c67..f6cf88b8 100644 --- a/include/aedis/response.hpp +++ b/include/aedis/response.hpp @@ -412,7 +412,8 @@ using response_flat_map = response_array; template > using response_flat_set = response_array; -class response_publish : public response_base { +template +class response_static_array : public response_base { private: int i = 0; void on_blob_string_impl(std::string_view s) override @@ -420,7 +421,7 @@ private: public: - std::array result; + std::array result; }; } // resp diff --git a/tests/general.cpp b/tests/general.cpp index 1f0414d9..4e5744f2 100644 --- a/tests/general.cpp +++ b/tests/general.cpp @@ -9,6 +9,9 @@ #include "test_stream.hpp" +// TODO: Use Beast test_stream and instantiate the test socket only +// once. + namespace net = aedis::net; using tcp = net::ip::tcp; using tcp_socket = net::use_awaitable_t<>::as_default_on_t; @@ -191,7 +194,7 @@ net::awaitable simple_string() test_tcp_socket ts {cmd}; resp::response_simple_string res; co_await resp::async_read(ts, buffer, res); - check_equal(res.result, {"OK"}, "simple_string (small)"); + check_equal(res.result, {"OK"}, "simple_string"); //check_equal(res.attribute.value, {}, "simple_string (empty attribute)"); } @@ -220,43 +223,59 @@ net::awaitable simple_string() //} } -net::awaitable offline() +net::awaitable number() { - // TODO: Use Beast test_stream and instantiate the test socket only - // once. - - std::string test_bulk(10000, 'a'); - - std::string bulk; - bulk += "$"; - bulk += std::to_string(std::size(test_bulk)); - bulk += "\r\n"; - bulk += test_bulk; - bulk += "\r\n"; - std::string buffer; - { - std::string cmd {"+OK\r\n"}; + { // int + std::string cmd {":-3\r\n"}; test_tcp_socket ts {cmd}; - resp::response_simple_string res; + resp::response_number res; co_await resp::async_read(ts, buffer, res); - check_equal(res.result, {"OK"}, "simple_string"); + check_equal(res.result, -3, "number (int)"); } - { + { // unsigned std::string cmd {":3\r\n"}; test_tcp_socket ts {cmd}; resp::response_number res; co_await resp::async_read(ts, buffer, res); - check_equal(res.result, 3, "number"); + check_equal(res.result, 3, "number (unsigned)"); } - { + { // std::size_t + std::string cmd {":1111111\r\n"}; + test_tcp_socket ts {cmd}; + resp::response_number res; + co_await resp::async_read(ts, buffer, res); + check_equal(res.result, 1111111, "number (std::size_t)"); + } +} + +net::awaitable array() +{ + std::string buffer; + { // Dynamic std::string cmd {"*3\r\n$3\r\none\r\n$3\r\ntwo\r\n$5\r\nthree\r\n"}; test_tcp_socket ts {cmd}; resp::response_array res; co_await resp::async_read(ts, buffer, res); - check_equal(res.result, {"one", "two", "three"}, "array"); + check_equal(res.result, {"one", "two", "three"}, "array (dynamic)"); + } + + { // Static + std::string cmd {"*3\r\n$3\r\none\r\n$3\r\ntwo\r\n$5\r\nthree\r\n"}; + test_tcp_socket ts {cmd}; + resp::response_static_array res; + co_await resp::async_read(ts, buffer, res); + check_equal(res.result, {"one", "two", "three"}, "array (static)"); + } + + { // Static int + std::string cmd {"*3\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n"}; + test_tcp_socket ts {cmd}; + resp::response_static_array res; + co_await resp::async_read(ts, buffer, res); + check_equal(res.result, {1, 2, 3}, "array (int)"); } { @@ -264,9 +283,13 @@ net::awaitable offline() test_tcp_socket ts {cmd}; resp::response_array res; co_await resp::async_read(ts, buffer, res); - check_equal(res.result, {}, "array (size 0)"); + check_equal(res.result, {}, "array (empty)"); } +} +net::awaitable blob_string() +{ + std::string buffer; { std::string cmd {"$2\r\nhh\r\n"}; test_tcp_socket ts {cmd}; @@ -290,16 +313,24 @@ net::awaitable offline() co_await resp::async_read(ts, buffer, res); check_equal(res.result, {}, "blob_string (size 0)"); } +} +net::awaitable simple_error() +{ + std::string buffer; { std::string cmd {"-Error\r\n"}; test_tcp_socket ts {cmd}; resp::response_base res; co_await resp::async_read(ts, buffer, res); check_equal(res.message(), {"Error"}, "simple_error (message)"); - check_equal(res.get_error(), resp::error::simple_error, "simple_error (enum)"); + check_equal(res.get_error(), resp::error::simple_error, "simple_error"); } +} +net::awaitable floating_point() +{ + std::string buffer; { std::string cmd {",1.23\r\n"}; test_tcp_socket ts {cmd}; @@ -324,6 +355,11 @@ net::awaitable offline() check_equal(res.result, {"-inf"}, "double (-inf)"); } +} + +net::awaitable boolean() +{ + std::string buffer; { std::string cmd {"#f\r\n"}; test_tcp_socket ts {cmd}; @@ -339,7 +375,11 @@ net::awaitable offline() co_await resp::async_read(ts, buffer, res); check_equal(res.result, true, "bool (true)"); } +} +net::awaitable blob_error() +{ + std::string buffer; { std::string cmd {"!21\r\nSYNTAX invalid syntax\r\n"}; test_tcp_socket ts {cmd}; @@ -357,7 +397,11 @@ net::awaitable offline() check_equal(res.message(), {}, "blob_error (empty message)"); check_equal(res.get_error(), resp::error::blob_error, "blob_error (enum)"); } +} +net::awaitable verbatim_string() +{ + std::string buffer; { std::string cmd {"=15\r\ntxt:Some string\r\n"}; test_tcp_socket ts {cmd}; @@ -367,13 +411,17 @@ net::awaitable offline() } { - std::string cmd {"(3492890328409238509324850943850943825024385\r\n"}; + std::string cmd {"=0\r\n\r\n"}; test_tcp_socket ts {cmd}; - resp::response_big_number res; + resp::response_verbatim_string res; co_await resp::async_read(ts, buffer, res); - check_equal(res.result, {"3492890328409238509324850943850943825024385"}, "big number"); + check_equal(res.result, {}, "verbatim_string (empty)"); } +} +net::awaitable set() +{ + std::string buffer; { std::string cmd {"~5\r\n+orange\r\n+apple\r\n+one\r\n+two\r\n+three\r\n"}; test_tcp_socket ts {cmd}; @@ -397,15 +445,11 @@ net::awaitable offline() co_await resp::async_read(ts, buffer, res); check_equal(res.result, {}, "set (empty)"); } +} - //{ - // std::string cmd {"|1\r\n+key-popularity\r\n%2\r\n$1\r\na\r\n,0.1923\r\n$1\r\nb\r\n,0.0012\r\n"}; - // test_tcp_socket ts {cmd}; - // resp::response_array res; - // co_await resp::async_read(ts, buffer, res); - // check_equal(res.result, {"key-popularity", "a", "0.1923", "b", "0.0012"}, "attribute"); - //} - +net::awaitable map() +{ + std::string buffer; { std::string cmd {"%7\r\n$6\r\nserver\r\n$5\r\nredis\r\n$7\r\nversion\r\n$5\r\n6.0.9\r\n$5\r\nproto\r\n:3\r\n$2\r\nid\r\n:203\r\n$4\r\nmode\r\n$10\r\nstandalone\r\n$4\r\nrole\r\n$6\r\nmaster\r\n$7\r\nmodules\r\n*0\r\n"}; test_tcp_socket ts {cmd}; @@ -421,23 +465,11 @@ net::awaitable offline() co_await resp::async_read(ts, buffer, res); check_equal(res.result, {}, "map (flat - empty)"); } +} - //{ - // std::string cmd {">4\r\n+pubsub\r\n+message\r\n+foo\r\n+bar\r\n"}; - // test_tcp_socket ts {cmd}; - // resp::response_array res; - // co_await resp::async_read(ts, buffer, res); - // check_equal(res.result, {"pubsub", "message", "foo", "bar"}, "push type"); - //} - - //{ - // std::string cmd {">0\r\n"}; - // test_tcp_socket ts {cmd}; - // resp::response_array res; - // co_await resp::async_read(ts, buffer, res); - // check_equal(res.result, {}, "push type (empty)"); - //} - +net::awaitable streamed_string() +{ + std::string buffer; { std::string cmd {"$?\r\n;4\r\nHell\r\n;5\r\no wor\r\n;1\r\nd\r\n;0\r\n"}; test_tcp_socket ts {cmd}; @@ -455,11 +487,48 @@ net::awaitable offline() } } +net::awaitable offline() +{ + std::string buffer; + //{ + // std::string cmd {"|1\r\n+key-popularity\r\n%2\r\n$1\r\na\r\n,0.1923\r\n$1\r\nb\r\n,0.0012\r\n"}; + // test_tcp_socket ts {cmd}; + // resp::response_array res; + // co_await resp::async_read(ts, buffer, res); + // check_equal(res.result, {"key-popularity", "a", "0.1923", "b", "0.0012"}, "attribute"); + //} + + //{ + // std::string cmd {">4\r\n+pubsub\r\n+message\r\n+foo\r\n+bar\r\n"}; + // test_tcp_socket ts {cmd}; + // resp::response_array res; + // co_await resp::async_read(ts, buffer, res); + // check_equal(res.result, {"pubsub", "message", "foo", "bar"}, "push type"); + //} + + //{ + // std::string cmd {">0\r\n"}; + // test_tcp_socket ts {cmd}; + // resp::response_array res; + // co_await resp::async_read(ts, buffer, res); + // check_equal(res.result, {}, "push type (empty)"); + //} +} + int main(int argc, char* argv[]) { net::io_context ioc {1}; co_spawn(ioc, simple_string(), net::detached); - co_spawn(ioc, offline(), net::detached); + co_spawn(ioc, number(), net::detached); + co_spawn(ioc, array(), net::detached); + co_spawn(ioc, blob_string(), net::detached); + co_spawn(ioc, simple_error(), net::detached); + co_spawn(ioc, floating_point(), net::detached); + co_spawn(ioc, boolean(), net::detached); + co_spawn(ioc, blob_error(), net::detached); + co_spawn(ioc, verbatim_string(), net::detached); + co_spawn(ioc, set(), net::detached); + co_spawn(ioc, map(), net::detached); co_spawn(ioc, test_list(), net::detached); co_spawn(ioc, test_set(), net::detached); ioc.run();