#include "../test.h"
#define TEST(name) TEST_CASE("parse-frames: " name, "[parse-frames]")
TEST("dies until established") {
CHECK_THROWS_AS(ServerParser().get_frames("asdasd"), Error);
CHECK_THROWS_AS(ClientParser().get_frames("asdasd"), Error);
}
TEST("basic") {
EstablishedServerParser p;
SECTION("small frame") {
test_frame(p, gen_frame().opcode(Opcode::BINARY).mask().final().payload("hello world"));
}
SECTION("medium frame") {
test_frame(p, gen_frame().opcode(Opcode::BINARY).mask().final().payload(repeat("1", 1024)));
}
SECTION("big frame") {
test_frame(p, gen_frame().opcode(Opcode::TEXT).mask().final().payload(repeat("1", 70000)));
}
SECTION("empty frame") {
test_frame(p, gen_frame().opcode(Opcode::TEXT).mask().final());
}
}
TEST("bad opcodes") {
EstablishedServerParser p;
for (int i = 3; i <= 7; ++i) { DYNAMIC_SECTION(i) {
test_frame(p, gen_frame().opcode((Opcode)i).mask().final().payload("hello world"), errc::invalid_opcode);
}}
}
TEST("max frame size") {
Parser::Config cfg;
cfg.max_frame_size = 1000;
EstablishedServerParser p(cfg);
SECTION("allowed") {
test_frame(p, gen_frame().opcode(Opcode::TEXT).mask().final().payload(repeat("1", 1000)));
}
SECTION("exceeds") {
test_frame(p, gen_frame().opcode(Opcode::TEXT).mask().final().payload(repeat("1", 1001)), errc::max_frame_size);
}
}
TEST("ping") {
EstablishedServerParser p;
SECTION("empty") {
test_frame(p, gen_frame().opcode(Opcode::PING).mask().final());
}
SECTION("payload") {
test_frame(p, gen_frame().opcode(Opcode::PING).mask().final().payload("pingdata"));
}
SECTION("fragmented") {
test_frame(p, gen_frame().opcode(Opcode::PING).mask(), errc::control_fragmented);
}
SECTION("long") {
test_frame(p, gen_frame().opcode(Opcode::PING).mask().final().payload(repeat("1", 1000)), errc::control_payload_too_big);
}
}
TEST("pong") {
EstablishedServerParser p;
SECTION("empty") {
test_frame(p, gen_frame().opcode(Opcode::PONG).mask().final());
}
SECTION("payload") {
test_frame(p, gen_frame().opcode(Opcode::PONG).mask().final().payload("pongdata"));
}
SECTION("fragmented") {
test_frame(p, gen_frame().opcode(Opcode::PONG).mask(), errc::control_fragmented);
}
SECTION("long") {
test_frame(p, gen_frame().opcode(Opcode::PONG).mask().final().payload(repeat("1", 1000)), errc::control_payload_too_big);
}
}
TEST("close") {
EstablishedServerParser p;
SECTION("empty") {
test_frame(p, gen_frame().opcode(Opcode::CLOSE).mask().final().close_code_check(CloseCode::UNKNOWN));
auto frames = get_frames(p, gen_frame().opcode(Opcode::TEXT).mask().final().str());
CHECK(frames.size() == 0); //no more frames available after close
}
SECTION("code") {
test_frame(p, gen_frame().opcode(Opcode::CLOSE).mask().final().close_code(CloseCode::DONE));
}
SECTION("message") {
test_frame(p, gen_frame().opcode(Opcode::CLOSE).mask().final().close_code(CloseCode::AWAY).payload("walk"));
}
SECTION("invalid payload") {
test_frame(p, gen_frame().opcode(Opcode::CLOSE).mask().final().payload("a"), errc::close_frame_invalid_data);
}
SECTION("fragmented") {
test_frame(p, gen_frame().opcode(Opcode::CLOSE).mask(), errc::control_fragmented);
}
SECTION("long") {
test_frame(p, gen_frame().opcode(Opcode::CLOSE).mask().final().close_code(CloseCode::AWAY).payload(repeat("1", 1000)), errc::control_payload_too_big);
}
SECTION("invalid close codes") {
for (auto code : {0, 999, 1004, (int)CloseCode::UNKNOWN, (int)CloseCode::ABNORMALLY, (int)CloseCode::TLS, 1100}) {
DYNAMIC_SECTION(string("code ") + panda::to_string(code)) {
test_frame(p, gen_frame().opcode(Opcode::CLOSE).mask().final().close_code(code).payload("a"), errc::close_frame_invalid_data);
}
}
}
SECTION("custom code") {
test_frame(p, gen_frame().opcode(Opcode::CLOSE).mask().final().close_code(3000));
}
}
TEST("2 frames") {
EstablishedServerParser p;
auto bin = gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa1").str() +
gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa2").str();
auto frames = get_frames(p, bin);
CHECK(frames.size() == 2);
CHECK_FRAME(frames[0]).final().payload("jopa1");
CHECK_FRAME(frames[1]).final().payload("jopa2");
}
TEST("3 frames") {
EstablishedServerParser p;
auto bin = gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa1").str() +
gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa2").str() +
gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa3").str();
auto frames = get_frames(p, bin);
CHECK(frames.size() == 3);
CHECK_FRAME(frames[0]).final().payload("jopa1");
CHECK_FRAME(frames[1]).final().payload("jopa2");
CHECK_FRAME(frames[2]).final().payload("jopa3");
}
TEST("2.5 frames + 1.5 frames") {
EstablishedServerParser p;
auto tmp = gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa3").str();
auto bin = gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa1").str() +
gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa2").str() +
tmp.substr(0, tmp.length()-1);
tmp.offset(tmp.length()-1);
auto frames = get_frames(p, bin);
CHECK(frames.size() == 2);
CHECK_FRAME(frames[0]).payload("jopa1");
CHECK_FRAME(frames[1]).payload("jopa2");
frames = get_frames(p, tmp + gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa4").str());
CHECK(frames.size() == 2);
CHECK_FRAME(frames[0]).payload("jopa3");
CHECK_FRAME(frames[1]).payload("jopa4");
}
TEST("initial frame in message with CONTINUE") {
EstablishedServerParser p;
test_frame(p, gen_frame().opcode(Opcode::CONTINUE).mask().final().payload("jopa"), errc::initial_continue);
}
TEST("fragment frame in message without CONTINUE") {
EstablishedServerParser p;
auto bin = gen_frame().opcode(Opcode::TEXT).mask().payload("p1").str() +
gen_frame().opcode(Opcode::TEXT).mask().payload("p2").str();
auto frames = get_frames(p, bin);
CHECK_FRAME(frames[0]).payload("p1");
CHECK(frames[1]->error() == ErrorCode(errc::fragment_no_continue));
bin = gen_frame().opcode(Opcode::BINARY).mask().payload("p1").str() +
gen_frame().opcode(Opcode::BINARY).mask().final().payload("p2").str();
frames = get_frames(p, bin);
CHECK(frames[1]->error() == ErrorCode(errc::fragment_no_continue)); // fin does not matter
}
TEST("mask") {
EstablishedServerParser sp;
EstablishedClientParser cp;
SECTION("unmasked frame in server parser") {
test_frame(sp, gen_frame().opcode(Opcode::TEXT).final().payload("jopa"), errc::not_masked);
}
SECTION("unmasked empty frame in server parser") {
test_frame(sp, gen_frame().opcode(Opcode::TEXT).final());
}
SECTION("masked frame in client parser") {
test_frame(cp, gen_frame().opcode(Opcode::TEXT).mask().final().payload("jopa"));
}
SECTION("unmasked frame in client parser") {
test_frame(cp, gen_frame().opcode(Opcode::TEXT).final().payload("jopa"));
}
}