// // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Test that header file is self-contained. #include #include #include #include #include #include namespace beast { namespace http { class message_test : public beast::unit_test::suite { public: struct Arg1 { bool moved = false; Arg1() = default; Arg1(Arg1&& other) { other.moved = true; } }; struct Arg2 { }; struct Arg3 { }; // default constructible Body struct default_body { using value_type = std::string; }; // 1-arg constructible Body struct one_arg_body { struct value_type { explicit value_type(Arg1 const&) { } explicit value_type(Arg1&& arg) { Arg1 arg_(std::move(arg)); } }; }; // 2-arg constructible Body struct two_arg_body { struct value_type { value_type(Arg1 const&, Arg2 const&) { } }; }; void testMessage() { static_assert(std::is_constructible< message>::value, ""); static_assert(std::is_constructible< message, Arg1>::value, ""); static_assert(std::is_constructible< message, Arg1 const>::value, ""); static_assert(std::is_constructible< message, Arg1 const&>::value, ""); static_assert(std::is_constructible< message, Arg1&&>::value, ""); static_assert(! std::is_constructible< message>::value, ""); static_assert(std::is_constructible< message, Arg1, fields::allocator_type>::value, ""); static_assert(std::is_constructible< message, std::piecewise_construct_t, std::tuple>::value, ""); static_assert(std::is_constructible< message, std::piecewise_construct_t, std::tuple>::value, ""); static_assert(std::is_constructible< message, std::piecewise_construct_t, std::tuple, std::tuple>::value, ""); { Arg1 arg1; message{std::move(arg1)}; BEAST_EXPECT(arg1.moved); } { fields h; h.insert("User-Agent", "test"); message m{Arg1{}, h}; BEAST_EXPECT(h["User-Agent"] == "test"); BEAST_EXPECT(m.fields["User-Agent"] == "test"); } { fields h; h.insert("User-Agent", "test"); message m{Arg1{}, std::move(h)}; BEAST_EXPECT(! h.exists("User-Agent")); BEAST_EXPECT(m.fields["User-Agent"] == "test"); } // swap message m1; message m2; m1.target("u"); m1.body = "1"; m1.fields.insert("h", "v"); m2.method("G"); m2.body = "2"; swap(m1, m2); BEAST_EXPECT(m1.method() == "G"); BEAST_EXPECT(m2.method().empty()); BEAST_EXPECT(m1.target().empty()); BEAST_EXPECT(m2.target() == "u"); BEAST_EXPECT(m1.body == "2"); BEAST_EXPECT(m2.body == "1"); BEAST_EXPECT(! m1.fields.exists("h")); BEAST_EXPECT(m2.fields.exists("h")); } struct MoveFields : fields { bool moved_to = false; bool moved_from = false; MoveFields() = default; MoveFields(MoveFields&& other) : moved_to(true) { other.moved_from = true; } MoveFields& operator=(MoveFields&& other) { return *this; } }; void testHeaders() { { using req_type = request_header; static_assert(std::is_copy_constructible::value, ""); static_assert(std::is_move_constructible::value, ""); static_assert(std::is_copy_assignable::value, ""); static_assert(std::is_move_assignable::value, ""); using res_type = response_header; static_assert(std::is_copy_constructible::value, ""); static_assert(std::is_move_constructible::value, ""); static_assert(std::is_copy_assignable::value, ""); static_assert(std::is_move_assignable::value, ""); } { MoveFields h; header r{std::move(h)}; BEAST_EXPECT(h.moved_from); BEAST_EXPECT(r.fields.moved_to); request m{std::move(r)}; BEAST_EXPECT(r.fields.moved_from); BEAST_EXPECT(m.fields.moved_to); } } void testFreeFunctions() { { request m; m.method("GET"); m.target("/"); m.version = 11; m.fields.insert("Upgrade", "test"); BEAST_EXPECT(! is_upgrade(m)); prepare(m, connection::upgrade); BEAST_EXPECT(is_upgrade(m)); BEAST_EXPECT(m.fields["Connection"] == "upgrade"); m.version = 10; BEAST_EXPECT(! is_upgrade(m)); } } void testPrepare() { request m; m.version = 10; BEAST_EXPECT(! is_upgrade(m)); m.fields.insert("Transfer-Encoding", "chunked"); try { prepare(m); fail(); } catch(std::exception const&) { } m.fields.erase("Transfer-Encoding"); m.fields.insert("Content-Length", "0"); try { prepare(m); fail(); } catch(std::exception const&) { pass(); } m.fields.erase("Content-Length"); m.fields.insert("Connection", "keep-alive"); try { prepare(m); fail(); } catch(std::exception const&) { pass(); } m.version = 11; m.fields.erase("Connection"); m.fields.insert("Connection", "close"); BEAST_EXPECT(! is_keep_alive(m)); } void testSwap() { message m1; message m2; m1.status = 200; m1.version = 10; m1.body = "1"; m1.fields.insert("h", "v"); m2.status = 404; m2.reason("OK"); m2.body = "2"; m2.version = 11; swap(m1, m2); BEAST_EXPECT(m1.status == 404); BEAST_EXPECT(m2.status == 200); BEAST_EXPECT(m1.reason() == "OK"); BEAST_EXPECT(m2.reason().empty()); BEAST_EXPECT(m1.version == 11); BEAST_EXPECT(m2.version == 10); BEAST_EXPECT(m1.body == "2"); BEAST_EXPECT(m2.body == "1"); BEAST_EXPECT(! m1.fields.exists("h")); BEAST_EXPECT(m2.fields.exists("h")); } void testSpecialMembers() { response r1; response r2{r1}; response r3{std::move(r2)}; r2 = r3; r1 = std::move(r2); [r1]() { }(); } void testReasonString() { for(int i = 1; i <= 999; ++i) BEAST_EXPECT(! reason_string(i).empty()); } void run() override { testMessage(); testHeaders(); testFreeFunctions(); testPrepare(); testSwap(); testSpecialMembers(); testReasonString(); } }; BEAST_DEFINE_TESTSUITE(message,http,beast); } // http } // beast