diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d976042..1a8ce19e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ 1.0.0-b12 +* BEAST_EXPECTS to add a reason string to test failures * Fix unit test runner to output all case names * Update README for build requirements * Rename to CHANGELOG.md diff --git a/extras/beast/unit_test/suite.hpp b/extras/beast/unit_test/suite.hpp index 1903ea66..ab12f1c6 100644 --- a/extras/beast/unit_test/suite.hpp +++ b/extras/beast/unit_test/suite.hpp @@ -9,6 +9,7 @@ #define BEAST_UNIT_TEST_SUITE_HPP #include +#include #include #include #include @@ -170,66 +171,93 @@ public: void operator()(runner& r); + /** Record a successful test condition. */ + template + void + pass(); + + /** Record a failure. + + @param reason + */ + template + void + fail(std::string const& reason = ""); + /** Evaluate a test condition. - The condition is passed as a template argument instead of `bool` so - that implicit conversion is not required. The `reason` argument is - logged if the condition is false. + This function provides improved logging by incorporating the + file name and line number into the reported output on failure, + as well as additional text specified by the caller. + + @param shouldBeTrue The condition to test. The condition + is evaluated in a boolean context. + + @param reason Optional added text to output on a failure. + + @param file The source code file where the test failed. + + @param line The source code line number where the test failed. + @return `true` if the test condition indicates success. */ - template - bool - expect(Condition const& shouldBeTrue, - String const& reason); - + /** @{ */ template bool expect(Condition const& shouldBeTrue) { - return expect(shouldBeTrue, ""); + return expect(shouldBeTrue, {}); } - /** Expect an exception from f() */ - /** @{ */ + template + bool + expect(Condition const& shouldBeTrue, std::string const& reason); + + template + bool + expect(Condition const& shouldBeTrue, + char const* file, int line) + { + return expect(shouldBeTrue, {}, file, line); + } + + template + bool + expect(Condition const& shouldBeTrue, + std::string const& reason, char const* file, int line); + /** @} */ + + // + // DEPRECATED + // + // Expect an exception from f() template bool except(F&& f, String const& reason); - template bool except(F&& f) { return except(f, ""); } - /** @} */ - - /** Expect an exception of the given type from f() */ - /** @{ */ template bool except(F&& f, String const& reason); - template bool except(F&& f) { return except(f, ""); } - /** @} */ - - /** Fail if f() throws */ - /** @{ */ template bool unexcept(F&& f, String const& reason); - template bool unexcept(F&& f) { return unexcept(f, ""); } - /** @} */ /** Return the argument associated with the runner. */ std::string const& @@ -252,16 +280,6 @@ public: return unexpected(shouldBeFalse, ""); } - /** Record a successful test condition. */ - template - void - pass(); - - /** Record a failure. */ - template - void - fail(std::string const& reason = ""); - private: friend class thread; @@ -368,7 +386,8 @@ suite::testcase_t::operator<<(T const& t) template void -suite::operator()(runner& r) +suite:: +operator()(runner& r) { *p_this_suite() = this; try @@ -383,11 +402,11 @@ suite::operator()(runner& r) } } -template -inline +template bool -suite::expect(Condition const& shouldBeTrue, - String const& reason) +suite:: +expect( + Condition const& shouldBeTrue, std::string const& reason) { if(shouldBeTrue) { @@ -398,9 +417,35 @@ suite::expect(Condition const& shouldBeTrue, return false; } +template +bool +suite:: +expect(Condition const& shouldBeTrue, + std::string const& reason, char const* file, int line) +{ + if(shouldBeTrue) + { + pass(); + return true; + } + std::string s; + if(! reason.empty()) + { + s += reason; + s += " "; + } + s += boost::filesystem::path{file}.filename().string() + + "(" + std::to_string(line) + ")"; + fail(s); + return false; +} + +// DEPRECATED + template bool -suite::except(F&& f, String const& reason) +suite:: +except(F&& f, String const& reason) { try { @@ -417,7 +462,8 @@ suite::except(F&& f, String const& reason) template bool -suite::except(F&& f, String const& reason) +suite:: +except(F&& f, String const& reason) { try { @@ -434,7 +480,8 @@ suite::except(F&& f, String const& reason) template bool -suite::unexcept(F&& f, String const& reason) +suite:: +unexcept(F&& f, String const& reason) { try { @@ -450,10 +497,10 @@ suite::unexcept(F&& f, String const& reason) } template -inline bool -suite::unexpected(Condition shouldBeFalse, - String const& reason) +suite:: +unexpected( + Condition shouldBeFalse, String const& reason) { bool const b = static_cast(shouldBeFalse); @@ -466,15 +513,18 @@ suite::unexpected(Condition shouldBeFalse, template void -suite::pass() +suite:: +pass() { propagate_abort(); runner_->pass(); } +// ::fail template void -suite::fail(std::string const& reason) +suite:: +fail(std::string const& reason) { propagate_abort(); runner_->fail(reason); @@ -487,7 +537,8 @@ suite::fail(std::string const& reason) inline void -suite::propagate_abort() +suite:: +propagate_abort() { if(abort_ && aborted_) throw abort_exception(); @@ -495,7 +546,8 @@ suite::propagate_abort() template void -suite::run(runner& r) +suite:: +run(runner& r) { runner_ = &r; @@ -520,10 +572,18 @@ suite::run(runner& r) #ifndef BEAST_EXPECT /** Check a precondition. + + If the condition is false, the file and line number are reported. */ -#define BEAST_EXPECT_S1(x) #x -#define BEAST_EXPECT_S2(x) BEAST_EXPECT_S1(x) -#define BEAST_EXPECT(cond) expect(cond, __FILE__ ":" BEAST_EXPECT_S2(__LINE__)) +#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__) +#endif + +#ifndef BEAST_EXPECTS +/** Check a precondition. + + If the condition is false, the file and line number are reported. +*/ +#define BEAST_EXPECTS(cond, reason) expect(cond, reason, __FILE__, __LINE__) #endif } // unit_test diff --git a/test/http/parser_bench.cpp b/test/http/parser_bench.cpp index aacda98d..c1840069 100644 --- a/test/http/parser_bench.cpp +++ b/test/http/parser_bench.cpp @@ -74,7 +74,7 @@ public: Parser p; error_code ec; p.write(sb.data(), ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) log << to_string(sb.data()) << std::endl; } } diff --git a/test/http/rfc7230.cpp b/test/http/rfc7230.cpp index c63fd8ae..49b1c952 100644 --- a/test/http/rfc7230.cpp +++ b/test/http/rfc7230.cpp @@ -56,7 +56,7 @@ public: [&](std::string const& s) { auto const got = str(param_list{s}); - expect(got == s, fmt(got)); + BEAST_EXPECTS(got == s, fmt(got)); }; auto const cs = [&](std::string const& s, std::string const& good) @@ -64,13 +64,13 @@ public: ce(good); auto const got = str(param_list{s}); ce(got); - expect(got == good, fmt(got)); + BEAST_EXPECTS(got == good, fmt(got)); }; auto const cq = [&](std::string const& s, std::string const& good) { auto const got = str(param_list{s}); - expect(got == good, fmt(got)); + BEAST_EXPECTS(got == good, fmt(got)); }; ce(""); @@ -114,7 +114,7 @@ public: [&](std::string const& s) { auto const got = str(ext_list{s}); - expect(got == s, fmt(got)); + BEAST_EXPECTS(got == s, fmt(got)); }; auto const cs = [&](std::string const& s, std::string const& good) @@ -122,13 +122,13 @@ public: ce(good); auto const got = str(ext_list{s}); ce(got); - expect(got == good, fmt(got)); + BEAST_EXPECTS(got == good, fmt(got)); }; auto const cq = [&](std::string const& s, std::string const& good) { auto const got = str(ext_list{s}); - expect(got == good, fmt(got)); + BEAST_EXPECTS(got == good, fmt(got)); }; /* ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] ) @@ -161,9 +161,9 @@ public: cq("ab;x=\" \"", "ab;x= "); cq("ab;x=\"\\\"\"", "ab;x=\""); - expect(ext_list{"a,b;i=1,c;j=2;k=3"}.exists("A")); - expect(ext_list{"a,b;i=1,c;j=2;k=3"}.exists("b")); - expect(! ext_list{"a,b;i=1,c;j=2;k=3"}.exists("d")); + BEAST_EXPECT(ext_list{"a,b;i=1,c;j=2;k=3"}.exists("A")); + BEAST_EXPECT(ext_list{"a,b;i=1,c;j=2;k=3"}.exists("b")); + BEAST_EXPECT(! ext_list{"a,b;i=1,c;j=2;k=3"}.exists("d")); // invalid strings cs("i j", "i"); @@ -193,7 +193,7 @@ public: [&](std::string const& s) { auto const got = str(token_list{s}); - expect(got == s, fmt(got)); + BEAST_EXPECTS(got == s, fmt(got)); }; auto const cs = [&](std::string const& s, std::string const& good) @@ -201,7 +201,7 @@ public: ce(good); auto const got = str(token_list{s}); ce(got); - expect(got == good, fmt(got)); + BEAST_EXPECTS(got == good, fmt(got)); }; cs("", ""); @@ -222,9 +222,9 @@ public: cs("x ,\ty ", "x,y"); cs("x, y, z", "x,y,z"); - expect(token_list{"a,b,c"}.exists("A")); - expect(token_list{"a,b,c"}.exists("b")); - expect(! token_list{"a,b,c"}.exists("d")); + BEAST_EXPECT(token_list{"a,b,c"}.exists("A")); + BEAST_EXPECT(token_list{"a,b,c"}.exists("b")); + BEAST_EXPECT(! token_list{"a,b,c"}.exists("d")); // invalid cs("x y", "x"); diff --git a/test/http/write.cpp b/test/http/write.cpp index 41360a60..f08c6b62 100644 --- a/test/http/write.cpp +++ b/test/http/write.cpp @@ -241,7 +241,7 @@ public: error_code ec; string_write_stream ss(ios_); async_write(ss, m, do_yield[ec]); - if(expect(! ec, ec.message())) + if(BEAST_EXPECTS(! ec, ec.message())) BEAST_EXPECT(ss.str == "HTTP/1.0 200 OK\r\n" "Server: test\r\n" @@ -260,7 +260,7 @@ public: error_code ec; string_write_stream ss(ios_); async_write(ss, m, do_yield[ec]); - if(expect(! ec, ec.message())) + if(BEAST_EXPECTS(! ec, ec.message())) BEAST_EXPECT(ss.str == "HTTP/1.1 200 OK\r\n" "Server: test\r\n" diff --git a/test/websocket/stream.cpp b/test/websocket/stream.cpp index 42e3d3d8..775c3c06 100644 --- a/test/websocket/stream.cpp +++ b/test/websocket/stream.cpp @@ -204,7 +204,7 @@ public: { } } - expect(n < limit); + BEAST_EXPECT(n < limit); } { // valid @@ -259,11 +259,11 @@ public: { ws.accept(boost::asio::buffer( s.substr(0, i), i)); - expect(! ev); + BEAST_EXPECTS(! ev, ev.message()); } catch(system_error const& se) { - expect(se.code() == ev); + BEAST_EXPECT(se.code() == ev); } } }; @@ -369,7 +369,7 @@ public: } catch(system_error const& se) { - expect(se.code() == error::response_failed); + BEAST_EXPECT(se.code() == error::response_failed); } }; // wrong HTTP version @@ -443,22 +443,22 @@ public: error_code ec; socket_type sock(ios_); sock.connect(ep, ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; stream ws(sock); ws.handshake("localhost", "/", ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; ws.write(boost::asio::buffer(v), ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; opcode op; streambuf db; ws.read(op, db, ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; - expect(to_string(db.data()) == - std::string{v.data(), v.size()}); + BEAST_EXPECT(to_string(db.data()) == + std::string(v.data(), v.size())); v.push_back(n+1); } } @@ -469,22 +469,22 @@ public: error_code ec; socket_type sock(ios_); sock.connect(ep, ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; stream ws(sock); ws.handshake("localhost", "/", ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; ws.async_write(boost::asio::buffer(v), do_yield[ec]); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; opcode op; streambuf db; ws.async_read(op, db, do_yield[ec]); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; - expect(to_string(db.data()) == - std::string{v.data(), v.size()}); + BEAST_EXPECT(to_string(db.data()) == + std::string(v.data(), v.size())); v.push_back(n+1); } } @@ -561,7 +561,7 @@ public: { ++count; // Send is canceled because close received. - expect(ec == boost::asio:: + BEAST_EXPECT(ec == boost::asio:: error::operation_aborted, ec.message()); // Writes after close are aborted. @@ -569,7 +569,7 @@ public: [&](error_code ec) { ++count; - expect(ec == boost::asio:: + BEAST_EXPECT(ec == boost::asio:: error::operation_aborted, ec.message()); }); @@ -583,7 +583,7 @@ public: break; ios.run_one(); } - expect(n < limit); + BEAST_EXPECT(n < limit); ios.run(); } #endif @@ -609,14 +609,14 @@ public: { // Read should fail with protocol error ++count; - expect(ec == error::failed, - ec.message()); + BEAST_EXPECTS( + ec == error::failed, ec.message()); // Reads after failure are aborted ws.async_read(op, db, [&](error_code ec) { ++count; - expect(ec == boost::asio:: + BEAST_EXPECTS(ec == boost::asio:: error::operation_aborted, ec.message()); }); @@ -631,7 +631,7 @@ public: { ++count; // Send is canceled because close received. - expect(ec == boost::asio:: + BEAST_EXPECTS(ec == boost::asio:: error::operation_aborted, ec.message()); // Writes after close are aborted. @@ -639,7 +639,7 @@ public: [&](error_code ec) { ++count; - expect(ec == boost::asio:: + BEAST_EXPECTS(ec == boost::asio:: error::operation_aborted, ec.message()); }); @@ -653,7 +653,7 @@ public: break; ios.run_one(); } - expect(n < limit); + BEAST_EXPECT(n < limit); ios.run(); } @@ -677,19 +677,19 @@ public: { // Read should complete with error::closed ++count; - expect(ec == error::closed, + BEAST_EXPECTS(ec == error::closed, ec.message()); // Pings after a close are aborted ws.async_ping("", [&](error_code ec) { ++count; - expect(ec == boost::asio:: + BEAST_EXPECTS(ec == boost::asio:: error::operation_aborted, ec.message()); }); }); - if(! expect(run_until(ios, 100, + if(! BEAST_EXPECT(run_until(ios, 100, [&]{ return ws.wr_close_; }))) return; // Try to ping @@ -698,7 +698,7 @@ public: { // Pings after a close are aborted ++count; - expect(ec == boost::asio:: + BEAST_EXPECTS(ec == boost::asio:: error::operation_aborted, ec.message()); // Subsequent calls to close are aborted @@ -706,7 +706,7 @@ public: [&](error_code ec) { ++count; - expect(ec == boost::asio:: + BEAST_EXPECTS(ec == boost::asio:: error::operation_aborted, ec.message()); }); @@ -719,7 +719,7 @@ public: break; ios.run_one(); } - expect(n < limit); + BEAST_EXPECT(n < limit); ios.run(); } @@ -740,7 +740,7 @@ public: [&](error_code ec) { ++count; - expect(ec == error::closed, + BEAST_EXPECTS(ec == error::closed, ec.message()); }); while(! ws.wr_block_) @@ -750,7 +750,7 @@ public: [&](error_code ec) { ++count; - expect(ec == boost::asio:: + BEAST_EXPECTS(ec == boost::asio:: error::operation_aborted, ec.message()); }); @@ -762,7 +762,7 @@ public: break; ios.run_one(); } - expect(n < limit); + BEAST_EXPECT(n < limit); ios.run(); } @@ -777,11 +777,11 @@ public: ws.async_write(sbuf("CLOSE"), [&](error_code ec) { - expect(! ec); + BEAST_EXPECT(! ec); ws.async_write(sbuf("PING"), [&](error_code ec) { - expect(! ec); + BEAST_EXPECT(! ec); }); }); opcode op; @@ -789,9 +789,9 @@ public: ws.async_read(op, db, [&](error_code ec) { - expect(ec == error::closed, ec.message()); + BEAST_EXPECTS(ec == error::closed, ec.message()); }); - if(! expect(run_until(ios, 100, + if(! BEAST_EXPECT(run_until(ios, 100, [&]{ return ios.stopped(); }))) return; } @@ -823,7 +823,7 @@ public: } error_code ec; ws.lowest_layer().connect(ep, ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) return false; ws.handshake("localhost", "/"); return true; @@ -834,7 +834,7 @@ public: // connect error_code ec; ws.lowest_layer().connect(ep, ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) return; } ws.handshake("localhost", "/"); @@ -848,8 +848,8 @@ public: opcode op; streambuf db; read(ws, op, db); - expect(op == opcode::text); - expect(to_string(db.data()) == "Hello"); + BEAST_EXPECT(op == opcode::text); + BEAST_EXPECT(to_string(db.data()) == "Hello"); } // close, no payload @@ -872,9 +872,9 @@ public: ws.set_option(pong_callback{ [&](ping_data const& payload) { - expect(! pong); + BEAST_EXPECT(! pong); pong = true; - expect(payload == ""); + BEAST_EXPECT(payload == ""); }}); ws.ping(""); ws.set_option(message_type(opcode::binary)); @@ -884,9 +884,9 @@ public: opcode op; streambuf db; ws.read(op, db); - expect(pong == 1); - expect(op == opcode::binary); - expect(to_string(db.data()) == "Hello"); + BEAST_EXPECT(pong == 1); + BEAST_EXPECT(op == opcode::binary); + BEAST_EXPECT(to_string(db.data()) == "Hello"); } ws.set_option(pong_callback{}); @@ -894,7 +894,7 @@ public: ws.set_option(pong_callback{ [&](ping_data const& payload) { - expect(payload == "payload"); + BEAST_EXPECT(payload == "payload"); }}); ws.ping("payload"); ws.write_frame(false, sbuf("Hello, ")); @@ -905,8 +905,8 @@ public: opcode op; streambuf db; ws.read(op, db); - expect(pong == 1); - expect(to_string(db.data()) == "Hello, World!"); + BEAST_EXPECT(pong == 1); + BEAST_EXPECT(to_string(db.data()) == "Hello, World!"); } ws.set_option(pong_callback{}); @@ -918,7 +918,7 @@ public: opcode op; streambuf db; ws.read(op, db); - expect(to_string(db.data()) == "Hello"); + BEAST_EXPECT(to_string(db.data()) == "Hello"); } ws.set_option(auto_fragment_size(0)); @@ -932,7 +932,7 @@ public: opcode op; streambuf db; ws.read(op, db); - expect(to_string(db.data()) == s); + BEAST_EXPECT(to_string(db.data()) == s); } } @@ -946,8 +946,8 @@ public: opcode op; streambuf db; ws.read(op, db); - expect(op == opcode::text); - expect(to_string(db.data()) == "Hello"); + BEAST_EXPECT(op == opcode::text); + BEAST_EXPECT(to_string(db.data()) == "Hello"); } // cause close @@ -1024,7 +1024,7 @@ public: } break; } - expect(n < limit); + BEAST_EXPECT(n < limit); } void testAsyncClient( @@ -1057,7 +1057,7 @@ public: ws.lowest_layer().close(ec); ec = {}; ws.lowest_layer().connect(ep, ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) return false; ws.async_handshake("localhost", "/", do_yield[ec]); if(ec) @@ -1070,7 +1070,7 @@ public: // connect ws.lowest_layer().connect(ep, ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) return; ws.async_handshake("localhost", "/", do_yield[ec]); if(ec) @@ -1089,8 +1089,8 @@ public: ws.async_read(op, db, do_yield[ec]); if(ec) throw system_error{ec}; - expect(op == opcode::text); - expect(to_string(db.data()) == "Hello"); + BEAST_EXPECT(op == opcode::text); + BEAST_EXPECT(to_string(db.data()) == "Hello"); } // close, no payload @@ -1120,9 +1120,9 @@ public: ws.set_option(pong_callback{ [&](ping_data const& payload) { - expect(! pong); + BEAST_EXPECT(! pong); pong = true; - expect(payload == ""); + BEAST_EXPECT(payload == ""); }}); ws.async_ping("", do_yield[ec]); if(ec) @@ -1137,8 +1137,8 @@ public: ws.async_read(op, db, do_yield[ec]); if(ec) throw system_error{ec}; - expect(op == opcode::binary); - expect(to_string(db.data()) == "Hello"); + BEAST_EXPECT(op == opcode::binary); + BEAST_EXPECT(to_string(db.data()) == "Hello"); ws.set_option(pong_callback{}); } @@ -1147,7 +1147,7 @@ public: ws.set_option(pong_callback{ [&](ping_data const& payload) { - expect(payload == "payload"); + BEAST_EXPECT(payload == "payload"); }}); ws.async_ping("payload", do_yield[ec]); if(! ec) @@ -1165,7 +1165,7 @@ public: ws.async_read(op, db, do_yield[ec]); if(ec) throw system_error{ec}; - expect(to_string(db.data()) == "Hello, World!"); + BEAST_EXPECT(to_string(db.data()) == "Hello, World!"); } ws.set_option(pong_callback{}); } @@ -1180,7 +1180,7 @@ public: ws.async_read(op, db, do_yield[ec]); if(ec) throw system_error{ec}; - expect(to_string(db.data()) == "Hello"); + BEAST_EXPECT(to_string(db.data()) == "Hello"); } ws.set_option(auto_fragment_size(0)); @@ -1198,7 +1198,7 @@ public: ws.async_read(op, db, do_yield[ec]); if(ec) throw system_error{ec}; - expect(to_string(db.data()) == s); + BEAST_EXPECT(to_string(db.data()) == s); } } @@ -1218,8 +1218,8 @@ public: ws.async_read(op, db, do_yield[ec]); if(ec) throw system_error{ec}; - expect(op == opcode::text); - expect(to_string(db.data()) == "Hello"); + BEAST_EXPECT(op == opcode::text); + BEAST_EXPECT(to_string(db.data()) == "Hello"); } // cause close @@ -1325,7 +1325,7 @@ public: } break; } - expect(n < limit); + BEAST_EXPECT(n < limit); } void testAsyncWriteFrame(endpoint_type const& ep) @@ -1336,11 +1336,11 @@ public: error_code ec; socket_type sock(ios); sock.connect(ep, ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; stream ws(sock); ws.handshake("localhost", "/", ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; ws.async_write_frame(false, boost::asio::null_buffers{}, @@ -1349,7 +1349,7 @@ public: fail(); }); ws.next_layer().cancel(ec); - if(! expect(! ec, ec.message())) + if(! BEAST_EXPECTS(! ec, ec.message())) break; // // Destruction of the io_service will cause destruction