LCOV - code coverage report
Current view: top level - src/test - mocket.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 73.1 % 93 68
Test Date: 2026-02-04 16:37:34 Functions: 83.3 % 12 10

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/corosio
       8              : //
       9              : 
      10              : #include <boost/corosio/test/mocket.hpp>
      11              : #include <boost/corosio/tcp_acceptor.hpp>
      12              : #include <boost/corosio/detail/config.hpp>
      13              : #include <boost/corosio/detail/except.hpp>
      14              : #include <boost/corosio/io_context.hpp>
      15              : #include <boost/capy/buffers/slice.hpp>
      16              : #include <boost/capy/ex/run_async.hpp>
      17              : #include <boost/capy/task.hpp>
      18              : #include <boost/capy/test/fuse.hpp>
      19              : 
      20              : #include <algorithm>
      21              : #include <cstdio>
      22              : #include <cstring>
      23              : 
      24              : namespace boost::corosio::test {
      25              : 
      26              : //------------------------------------------------------------------------------
      27              : 
      28            8 : mocket::
      29              : ~mocket() = default;
      30              : 
      31            4 : mocket::
      32              : mocket(
      33              :     capy::execution_context& ctx,
      34              :     capy::test::fuse& f,
      35              :     std::size_t max_read_size,
      36            4 :     std::size_t max_write_size)
      37            4 :     : sock_(ctx)
      38            4 :     , fuse_(&f)
      39            4 :     , max_read_size_(max_read_size)
      40            4 :     , max_write_size_(max_write_size)
      41              : {
      42            4 :     if (max_read_size == 0)
      43            0 :         detail::throw_logic_error("mocket: max_read_size cannot be 0");
      44            4 :     if (max_write_size == 0)
      45            0 :         detail::throw_logic_error("mocket: max_write_size cannot be 0");
      46            4 : }
      47              : 
      48            4 : mocket::
      49            4 : mocket(mocket&& other) noexcept
      50            4 :     : sock_(std::move(other.sock_))
      51            4 :     , provide_(std::move(other.provide_))
      52            4 :     , expect_(std::move(other.expect_))
      53            4 :     , fuse_(other.fuse_)
      54            4 :     , max_read_size_(other.max_read_size_)
      55            4 :     , max_write_size_(other.max_write_size_)
      56              : {
      57            4 :     other.fuse_ = nullptr;
      58            4 : }
      59              : 
      60              : mocket&
      61            0 : mocket::
      62              : operator=(mocket&& other) noexcept
      63              : {
      64            0 :     if (this != &other)
      65              :     {
      66            0 :         sock_ = std::move(other.sock_);
      67            0 :         provide_ = std::move(other.provide_);
      68            0 :         expect_ = std::move(other.expect_);
      69            0 :         fuse_ = other.fuse_;
      70            0 :         max_read_size_ = other.max_read_size_;
      71            0 :         max_write_size_ = other.max_write_size_;
      72            0 :         other.fuse_ = nullptr;
      73              :     }
      74            0 :     return *this;
      75              : }
      76              : 
      77              : void
      78            2 : mocket::
      79              : provide(std::string s)
      80              : {
      81            2 :     provide_.append(std::move(s));
      82            2 : }
      83              : 
      84              : void
      85            2 : mocket::
      86              : expect(std::string s)
      87              : {
      88            2 :     expect_.append(std::move(s));
      89            2 : }
      90              : 
      91              : std::error_code
      92            4 : mocket::
      93              : close()
      94              : {
      95            4 :     if (!sock_.is_open())
      96            0 :         return {};
      97              : 
      98              :     // Verify test expectations
      99            4 :     if (!expect_.empty())
     100              :     {
     101            1 :         fuse_->fail();
     102            1 :         sock_.close();
     103            1 :         return capy::error::test_failure;
     104              :     }
     105            3 :     if (!provide_.empty())
     106              :     {
     107            1 :         fuse_->fail();
     108            1 :         sock_.close();
     109            1 :         return capy::error::test_failure;
     110              :     }
     111              : 
     112            2 :     sock_.close();
     113            2 :     return {};
     114              : }
     115              : 
     116              : void
     117            0 : mocket::
     118              : cancel()
     119              : {
     120            0 :     sock_.cancel();
     121            0 : }
     122              : 
     123              : bool
     124            1 : mocket::
     125              : is_open() const noexcept
     126              : {
     127            1 :     return sock_.is_open();
     128              : }
     129              : 
     130              : //------------------------------------------------------------------------------
     131              : 
     132              : std::pair<mocket, tcp_socket>
     133            4 : make_mocket_pair(
     134              :     capy::execution_context& ctx,
     135              :     capy::test::fuse& f,
     136              :     std::size_t max_read_size,
     137              :     std::size_t max_write_size)
     138              : {
     139            4 :     auto& ioc = static_cast<io_context&>(ctx);
     140            4 :     auto ex = ioc.get_executor();
     141              : 
     142              :     // Create the mocket
     143            4 :     mocket m(ctx, f, max_read_size, max_write_size);
     144              : 
     145              :     // Create the peer socket
     146            4 :     tcp_socket peer(ctx);
     147              : 
     148            4 :     std::error_code accept_ec;
     149            4 :     std::error_code connect_ec;
     150            4 :     bool accept_done = false;
     151            4 :     bool connect_done = false;
     152              : 
     153              :     // Use ephemeral port (0) - OS assigns an available port
     154            4 :     tcp_acceptor acc(ctx);
     155            4 :     acc.listen(endpoint(ipv4_address::loopback(), 0));
     156            4 :     auto port = acc.local_endpoint().port();
     157              : 
     158              :     // Open peer socket for connect
     159            4 :     peer.open();
     160              : 
     161              :     // Create a tcp_socket to receive the accepted connection
     162            4 :     tcp_socket accepted_socket(ctx);
     163              : 
     164              :     // Launch accept operation
     165            8 :     capy::run_async(ex)(
     166            4 :         [](tcp_acceptor& a, tcp_socket& s,
     167              :            std::error_code& ec_out, bool& done_out) -> capy::task<>
     168              :         {
     169              :             auto [ec] = co_await a.accept(s);
     170              :             ec_out = ec;
     171              :             done_out = true;
     172           16 :         }(acc, accepted_socket, accept_ec, accept_done));
     173              : 
     174              :     // Launch connect operation
     175            8 :     capy::run_async(ex)(
     176            4 :         [](tcp_socket& s, endpoint ep,
     177              :            std::error_code& ec_out, bool& done_out) -> capy::task<>
     178              :         {
     179              :             auto [ec] = co_await s.connect(ep);
     180              :             ec_out = ec;
     181              :             done_out = true;
     182           16 :         }(peer, endpoint(ipv4_address::loopback(), port),
     183              :           connect_ec, connect_done));
     184              : 
     185              :     // Run until both complete
     186            4 :     ioc.run();
     187            4 :     ioc.restart();
     188              : 
     189              :     // Check for errors
     190            4 :     if (!accept_done || accept_ec)
     191              :     {
     192            0 :         std::fprintf(stderr, "make_mocket_pair: accept failed (done=%d, ec=%s)\n",
     193            0 :             accept_done, accept_ec.message().c_str());
     194            0 :         acc.close();
     195            0 :         throw std::runtime_error("mocket accept failed");
     196              :     }
     197              : 
     198            4 :     if (!connect_done || connect_ec)
     199              :     {
     200            0 :         std::fprintf(stderr, "make_mocket_pair: connect failed (done=%d, ec=%s)\n",
     201            0 :             connect_done, connect_ec.message().c_str());
     202            0 :         acc.close();
     203            0 :         accepted_socket.close();
     204            0 :         throw std::runtime_error("mocket connect failed");
     205              :     }
     206              : 
     207              :     // Transfer the accepted socket to mocket
     208            4 :     m.socket() = std::move(accepted_socket);
     209              : 
     210            4 :     acc.close();
     211              : 
     212            8 :     return {std::move(m), std::move(peer)};
     213            4 : }
     214              : 
     215              : } // namespace boost::corosio::test
        

Generated by: LCOV version 2.3