#pragma once
#include <panda/optional.h>
#include <panda/protocol/websocket.h>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
namespace test {
using namespace panda;
using namespace panda::protocol::websocket;
using panda::protocol::http::Headers;
struct ReMatcher : Catch::Matchers::MatcherBase<string> {
ReMatcher (const string& regex, bool case_sen = false) : re(regex), case_sen(case_sen) {}
bool match (const string& matchee) const override;
std::string describe () const override;
private:
string re;
bool case_sen;
};
inline ReMatcher MatchesRe (const string& regex, bool case_sen = false) { return ReMatcher(regex, case_sen); }
void regex_replace (string&, const std::string&, const std::string&);
template <class T>
string join (T&& v) {
string ret;
for (auto& s : v) ret += s;
return ret;
}
string repeat (string_view, int);
std::vector<string> accept_packet ();
inline string accept_packet_s () { return join(accept_packet()); }
struct EstablishedServerParser : ServerParser {
EstablishedServerParser (bool deflate = false) : EstablishedServerParser({}, deflate) {}
EstablishedServerParser (const Parser::Config& cfg, bool deflate = false);
};
struct EstablishedClientParser : ClientParser {
EstablishedClientParser (bool deflate = false) : EstablishedClientParser({}, deflate) {}
EstablishedClientParser (const Parser::Config& cfg, bool deflate = false);
};
struct FMChecker {
FMChecker (FrameSP f) : _frame(f) {}
FMChecker (MessageSP m) : _message(m) {}
FMChecker& opcode (Opcode v) { _opcode = v; return *this; }
FMChecker& final (bool v) { _fin = v; return *this; }
FMChecker& final () { return final(true); }
FMChecker& rsv1 () { _rsv1 = true; return *this; }
FMChecker& rsv2 () { _rsv2 = true; return *this; }
FMChecker& rsv3 () { _rsv3 = true; return *this; }
FMChecker& payload (string v) { _payload = v; return *this; }
FMChecker& paylen (size_t v) { _paylen = v; return *this; }
FMChecker& nframes (uint32_t v) { _nframes = v; return *this; }
FMChecker& close_code (int v) { _close_code = v; return *this; }
FMChecker& close_message (string v) { _close_message = v; return *this; }
~FMChecker () noexcept(false);
private:
FrameSP _frame;
MessageSP _message;
optional<Opcode> _opcode;
optional<bool> _fin;
optional<bool> _rsv1;
optional<bool> _rsv2;
optional<bool> _rsv3;
optional<string> _payload;
optional<size_t> _paylen;
optional<int> _close_code;
optional<string> _close_message;
optional<uint32_t> _nframes;
};
inline FMChecker CHECK_FRAME (FrameSP f) { return FMChecker(f); }
inline FMChecker CHECK_MESSAGE (MessageSP m) { return FMChecker(m); }
struct FrameGenerator {
FrameGenerator () {}
FrameGenerator (string bin) : _bin(bin) {}
FrameGenerator& opcode (Opcode v) { _opcode = v; return *this; }
FrameGenerator& mask (string v) { _mask = v; return *this; }
FrameGenerator& mask () { return mask("autogen"); }
FrameGenerator& final (bool v) { _final = v; return *this; }
FrameGenerator& final () { return final(true); }
FrameGenerator& rsv1 () { _rsv1 = true; return *this; }
FrameGenerator& rsv2 () { _rsv2 = true; return *this; }
FrameGenerator& rsv3 () { _rsv3 = true; return *this; }
FrameGenerator& payload (string v) { _payload = v; return *this; }
FrameGenerator& nframes (uint32_t v) { _nframes = v; return *this; }
FrameGenerator& close_code (int v) { _close_code = v; return *this; }
FrameGenerator& close_code_check (int v) { _close_code_check = v; return *this; }
FrameGenerator& binlen (size_t v) { _binlen = v; return *this; }
Opcode opcode () const { return _opcode; }
string is_masked () const { return _mask; }
bool is_final () const { return _final; }
bool has_rsv1 () const { return _rsv1; }
bool has_rsv2 () const { return _rsv2; }
bool has_rsv3 () const { return _rsv3; }
string payload () const { return _payload; }
uint32_t nframes () const { return _nframes; }
int close_code () const { return _close_code; }
int close_code_check () const { return _close_code_check; }
size_t binlen () const { return _binlen; }
operator string () const { return str(); }
string str() const;
std::vector<string> vec() const;
FrameGenerator& msg_mode () { _msg_mode = true; return *this; }
~FrameGenerator () noexcept(false);
private:
Opcode _opcode = Opcode::TEXT;
string _mask;
bool _final = false;
bool _rsv1 = false;
bool _rsv2 = false;
bool _rsv3 = false;
string _payload;
int _close_code = 0;
int _close_code_check = 0;
uint32_t _nframes = 1;
bool _msg_mode = false;
string _bin;
size_t _binlen = 0;
string _gen_frame () const;
std::vector<string> _gen_message () const;
};
inline FrameGenerator gen_frame () { return {}; }
inline FrameGenerator gen_message () { return FrameGenerator().msg_mode(); }
inline FrameGenerator CHECK_BINFRAME (string bin) { return FrameGenerator(bin); }
inline FrameSP get_frame (Parser& parser, string str = {}) {
auto range = parser.get_frames(str);
if (range.begin() == range.end()) return {};
return *(range.begin());
}
inline std::vector<FrameSP> get_frames (Parser& parser, string str = {}) {
std::vector<FrameSP> ret;
auto frames = parser.get_frames(str);
for (auto f : frames) ret.push_back(f);
return ret;
}
inline MessageSP get_message (Parser& parser, string str = {}) {
auto msgs = parser.get_messages(str);
if (msgs.begin() == msgs.end()) return {};
return *(msgs.begin());
}
inline std::vector<MessageSP> get_messages (Parser& parser, string str = {}) {
std::vector<MessageSP> ret;
auto msgs = parser.get_messages(str);
for (auto m : msgs) ret.push_back(m);
return ret;
}
void reset (Parser&);
void test_frame (Parser&, FrameGenerator, const ErrorCode& = {}, int suggested_close_code = 0);
MessageSP test_message (Parser&, FrameGenerator, const ErrorCode& = {});
}
using namespace test;
using namespace Catch::Matchers;
namespace panda { namespace protocol { namespace websocket {
inline bool operator== (const HeaderValue& lhs, const HeaderValue& rhs) {
return lhs.name == rhs.name && lhs.params == rhs.params;
}
}}}