2021-09-10 22:46:52 +00:00
/*
* Copyright ( c ) 2021 , sin - ack < sin - ack @ protonmail . com >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <AK/Format.h>
2023-01-22 03:24:18 +00:00
# include <AK/MaybeOwned.h>
2022-12-07 16:43:31 +00:00
# include <AK/String.h>
2021-09-10 22:46:52 +00:00
# include <LibCore/EventLoop.h>
2023-02-09 02:02:46 +00:00
# include <LibCore/File.h>
2021-09-10 22:46:52 +00:00
# include <LibCore/LocalServer.h>
2023-02-08 22:05:44 +00:00
# include <LibCore/Socket.h>
2021-09-10 22:46:52 +00:00
# include <LibCore/TCPServer.h>
# include <LibCore/Timer.h>
# include <LibCore/UDPServer.h>
# include <LibTest/TestCase.h>
# include <LibThreading/BackgroundAction.h>
# include <fcntl.h>
# include <unistd.h>
// File tests
TEST_CASE ( file_open )
{
2023-02-09 02:02:46 +00:00
auto maybe_file = Core : : File : : open ( " /tmp/file-open-test.txt " sv , Core : : File : : OpenMode : : Write ) ;
2021-09-10 22:46:52 +00:00
if ( maybe_file . is_error ( ) ) {
warnln ( " Failed to open the file: {} " , strerror ( maybe_file . error ( ) . code ( ) ) ) ;
VERIFY_NOT_REACHED ( ) ;
}
// Testing out some basic file properties.
auto file = maybe_file . release_value ( ) ;
2021-12-29 22:31:45 +00:00
EXPECT ( file - > is_open ( ) ) ;
EXPECT ( ! file - > is_eof ( ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto size = TRY_OR_FAIL ( file - > size ( ) ) ;
EXPECT_EQ ( size , 0ul ) ;
2021-09-10 22:46:52 +00:00
}
TEST_CASE ( file_write_bytes )
{
2023-05-07 18:14:06 +00:00
auto file = TRY_OR_FAIL ( Core : : File : : open ( " /tmp/file-write-bytes-test.txt " sv , Core : : File : : OpenMode : : Write ) ) ;
2021-09-10 22:46:52 +00:00
constexpr auto some_words = " These are some words " sv ;
ReadonlyBytes buffer { some_words . characters_without_null_termination ( ) , some_words . length ( ) } ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > write_some ( buffer ) ) ;
2021-09-10 22:46:52 +00:00
}
constexpr auto expected_buffer_contents = " <small>(Please consider translating this message for the benefit of your fellow Wikimedians. Please also consider translating " sv ;
TEST_CASE ( file_read_bytes )
{
2023-05-07 18:14:06 +00:00
auto file = TRY_OR_FAIL ( Core : : File : : open ( " /usr/Tests/LibCore/long_lines.txt " sv , Core : : File : : OpenMode : : Read ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( 131 ) ) ;
2021-09-10 22:46:52 +00:00
2023-02-24 21:38:01 +00:00
auto result = file - > read_some ( buffer ) ;
2023-05-07 18:14:06 +00:00
EXPECT_EQ ( TRY_OR_FAIL ( result ) . size ( ) , 131ul ) ;
2021-09-10 22:46:52 +00:00
StringView buffer_contents { buffer . bytes ( ) } ;
EXPECT_EQ ( buffer_contents , expected_buffer_contents ) ;
}
constexpr auto expected_seek_contents1 = " |Lleer esti mens " sv ;
constexpr auto expected_seek_contents2 = " s of advanced ad " sv ;
constexpr auto expected_seek_contents3 = " levels of advanc " sv ;
TEST_CASE ( file_seeking_around )
{
2023-05-07 18:14:06 +00:00
auto file = TRY_OR_FAIL ( Core : : File : : open ( " /usr/Tests/LibCore/long_lines.txt " sv , Core : : File : : OpenMode : : Read ) ) ;
2021-09-10 22:46:52 +00:00
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( file - > size ( ) . release_value ( ) , 8702ul ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( 16 ) ) ;
2021-09-10 22:46:52 +00:00
StringView buffer_contents { buffer . bytes ( ) } ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > seek ( 500 , SeekMode : : SetPosition ) ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( file - > tell ( ) . release_value ( ) , 500ul ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > read_until_filled ( buffer ) ) ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( buffer_contents , expected_seek_contents1 ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > seek ( 234 , SeekMode : : FromCurrentPosition ) ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( file - > tell ( ) . release_value ( ) , 750ul ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > read_until_filled ( buffer ) ) ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( buffer_contents , expected_seek_contents2 ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > seek ( - 105 , SeekMode : : FromEndPosition ) ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( file - > tell ( ) . release_value ( ) , 8597ul ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > read_until_filled ( buffer ) ) ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( buffer_contents , expected_seek_contents3 ) ;
}
2023-07-06 11:41:38 +00:00
BENCHMARK_CASE ( file_tell )
{
auto file = TRY_OR_FAIL ( Core : : File : : open ( " /usr/Tests/LibCore/10kb.txt " sv , Core : : File : : OpenMode : : Read ) ) ;
auto expected_file_offset = 0u ;
auto ten_byte_buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( 1 ) ) ;
for ( auto i = 0u ; i < 4000 ; + + i ) {
TRY_OR_FAIL ( file - > read_until_filled ( ten_byte_buffer ) ) ;
expected_file_offset + = 1u ;
EXPECT_EQ ( expected_file_offset , TRY_OR_FAIL ( file - > tell ( ) ) ) ;
}
for ( auto i = 0u ; i < 4000 ; + + i ) {
auto seek_file_offset = TRY_OR_FAIL ( file - > seek ( - 1 , SeekMode : : FromCurrentPosition ) ) ;
expected_file_offset - = 1 ;
EXPECT_EQ ( seek_file_offset , TRY_OR_FAIL ( file - > tell ( ) ) ) ;
EXPECT_EQ ( expected_file_offset , TRY_OR_FAIL ( file - > tell ( ) ) ) ;
}
}
2023-07-04 15:47:23 +00:00
TEST_CASE ( file_buffered_write_and_seek )
{
auto file = TRY_OR_FAIL ( Core : : OutputBufferedFile : : create ( TRY_OR_FAIL ( Core : : File : : open ( " /tmp/file-buffered-write-test.txt " sv , Core : : File : : OpenMode : : Truncate | Core : : File : : OpenMode : : ReadWrite ) ) ) ) ;
TRY_OR_FAIL ( file - > write_some ( " 0123456789 " sv . bytes ( ) ) ) ;
EXPECT_EQ ( file - > tell ( ) . release_value ( ) , 10ul ) ;
// Reads don't go through the buffer, so after we seek, the data must be available from the underlying file.
TRY_OR_FAIL ( file - > seek ( 0 , AK : : SeekMode : : SetPosition ) ) ;
auto first_byte = TRY_OR_FAIL ( file - > read_value < u8 > ( ) ) ;
EXPECT_EQ ( first_byte , static_cast < u8 > ( ' 0 ' ) ) ;
TRY_OR_FAIL ( file - > seek ( 9 , AK : : SeekMode : : SetPosition ) ) ;
auto last_byte = TRY_OR_FAIL ( file - > read_value < u8 > ( ) ) ;
EXPECT_EQ ( last_byte , static_cast < u8 > ( ' 9 ' ) ) ;
EXPECT_EQ ( file - > tell ( ) . release_value ( ) , 10ul ) ;
}
2021-09-10 22:46:52 +00:00
TEST_CASE ( file_adopt_fd )
{
int rc = : : open ( " /usr/Tests/LibCore/long_lines.txt " , O_RDONLY ) ;
EXPECT ( rc > = 0 ) ;
2023-05-07 18:14:06 +00:00
auto file = TRY_OR_FAIL ( Core : : File : : adopt_fd ( rc , Core : : File : : OpenMode : : Read ) ) ;
2021-09-10 22:46:52 +00:00
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( file - > size ( ) . release_value ( ) , 8702ul ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( 16 ) ) ;
2021-09-10 22:46:52 +00:00
StringView buffer_contents { buffer . bytes ( ) } ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > seek ( 500 , SeekMode : : SetPosition ) ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( file - > tell ( ) . release_value ( ) , 500ul ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > read_until_filled ( buffer ) ) ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( buffer_contents , expected_seek_contents1 ) ;
// A single seek & read test should be fine for now.
}
TEST_CASE ( file_adopt_invalid_fd )
{
2023-02-09 02:02:46 +00:00
auto maybe_file = Core : : File : : adopt_fd ( - 1 , Core : : File : : OpenMode : : Read ) ;
2021-09-10 22:46:52 +00:00
EXPECT ( maybe_file . is_error ( ) ) ;
EXPECT_EQ ( maybe_file . error ( ) . code ( ) , EBADF ) ;
}
2022-02-03 19:21:51 +00:00
TEST_CASE ( file_truncate )
{
2023-05-07 18:14:06 +00:00
auto file = TRY_OR_FAIL ( Core : : File : : open ( " /tmp/file-truncate-test.txt " sv , Core : : File : : OpenMode : : Write ) ) ;
2022-02-03 19:21:51 +00:00
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > truncate ( 999 ) ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( file - > size ( ) . release_value ( ) , 999ul ) ;
2022-02-03 19:21:51 +00:00
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > truncate ( 42 ) ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( file - > size ( ) . release_value ( ) , 42ul ) ;
2022-02-03 19:21:51 +00:00
}
2021-09-10 22:46:52 +00:00
// TCPSocket tests
2022-01-18 13:25:51 +00:00
TEST_CASE ( should_error_when_connection_fails )
{
2023-02-08 22:05:44 +00:00
// NOTE: This is required here because Core::TCPSocket requires
2022-01-18 13:25:51 +00:00
// Core::EventLoop through Core::Notifier.
Core : : EventLoop event_loop ;
2023-02-08 22:05:44 +00:00
auto maybe_tcp_socket = Core : : TCPSocket : : connect ( { { 127 , 0 , 0 , 1 } , 1234 } ) ;
2022-01-18 13:25:51 +00:00
EXPECT ( maybe_tcp_socket . is_error ( ) ) ;
EXPECT ( maybe_tcp_socket . error ( ) . is_syscall ( ) ) ;
EXPECT ( maybe_tcp_socket . error ( ) . code ( ) = = ECONNREFUSED ) ;
}
2021-09-10 22:46:52 +00:00
constexpr auto sent_data = " Mr. Watson, come here. I want to see you. " sv ;
TEST_CASE ( tcp_socket_read )
{
// NOTE: This is required here because Core::TCPServer requires
// Core::EventLoop through Core::Notifier.
Core : : EventLoop event_loop ;
2023-05-07 18:14:06 +00:00
auto tcp_server = TRY_OR_FAIL ( Core : : TCPServer : : try_create ( ) ) ;
TRY_OR_FAIL ( tcp_server - > listen ( { 127 , 0 , 0 , 1 } , 9090 ) ) ;
TRY_OR_FAIL ( tcp_server - > set_blocking ( true ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto client_socket = TRY_OR_FAIL ( Core : : TCPSocket : : connect ( { { 127 , 0 , 0 , 1 } , 9090 } ) ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > is_open ( ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto server_socket = TRY_OR_FAIL ( tcp_server - > accept ( ) ) ;
TRY_OR_FAIL ( server_socket - > write_some ( { sent_data . characters_without_null_termination ( ) , sent_data . length ( ) } ) ) ;
2021-12-29 22:31:45 +00:00
server_socket - > close ( ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > can_read_without_blocking ( 100 ) . release_value ( ) ) ;
EXPECT_EQ ( client_socket - > pending_bytes ( ) . release_value ( ) , sent_data . length ( ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto receive_buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( 64 ) ) ;
auto read_bytes = TRY_OR_FAIL ( client_socket - > read_some ( receive_buffer ) ) ;
2021-09-10 22:46:52 +00:00
2022-04-15 12:33:02 +00:00
StringView received_data { read_bytes } ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( sent_data , received_data ) ;
}
TEST_CASE ( tcp_socket_write )
{
Core : : EventLoop event_loop ;
2023-05-07 18:14:06 +00:00
auto tcp_server = TRY_OR_FAIL ( Core : : TCPServer : : try_create ( ) ) ;
TRY_OR_FAIL ( tcp_server - > listen ( { 127 , 0 , 0 , 1 } , 9090 ) ) ;
TRY_OR_FAIL ( tcp_server - > set_blocking ( true ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto client_socket = TRY_OR_FAIL ( Core : : TCPSocket : : connect ( { { 127 , 0 , 0 , 1 } , 9090 } ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto server_socket = TRY_OR_FAIL ( tcp_server - > accept ( ) ) ;
TRY_OR_FAIL ( server_socket - > set_blocking ( true ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( client_socket - > write_until_depleted ( { sent_data . characters_without_null_termination ( ) , sent_data . length ( ) } ) ) ;
2021-12-29 22:31:45 +00:00
client_socket - > close ( ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto receive_buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( 64 ) ) ;
auto read_bytes = TRY_OR_FAIL ( server_socket - > read_some ( receive_buffer ) ) ;
2021-09-10 22:46:52 +00:00
2022-04-15 12:33:02 +00:00
StringView received_data { read_bytes } ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( sent_data , received_data ) ;
}
TEST_CASE ( tcp_socket_eof )
{
Core : : EventLoop event_loop ;
2023-05-07 18:14:06 +00:00
auto tcp_server = TRY_OR_FAIL ( Core : : TCPServer : : try_create ( ) ) ;
TRY_OR_FAIL ( tcp_server - > listen ( { 127 , 0 , 0 , 1 } , 9090 ) ) ;
TRY_OR_FAIL ( tcp_server - > set_blocking ( true ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto client_socket = TRY_OR_FAIL ( Core : : TCPSocket : : connect ( { { 127 , 0 , 0 , 1 } , 9090 } ) ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > is_open ( ) ) ;
2021-09-10 22:46:52 +00:00
auto server_socket = tcp_server - > accept ( ) . release_value ( ) ;
2021-12-29 22:31:45 +00:00
server_socket - > close ( ) ;
2021-09-10 22:46:52 +00:00
// NOTE: This may seem unintuitive, but poll will mark a fd which has
// reached EOF (i.e. in the case of the other side disconnecting) as
// POLLIN.
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > can_read_without_blocking ( 100 ) . release_value ( ) ) ;
EXPECT_EQ ( client_socket - > pending_bytes ( ) . release_value ( ) , 0ul ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto receive_buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( 1 ) ) ;
2023-02-24 21:38:01 +00:00
EXPECT ( client_socket - > read_some ( receive_buffer ) . release_value ( ) . is_empty ( ) ) ;
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > is_eof ( ) ) ;
2021-09-10 22:46:52 +00:00
}
// UDPSocket tests
constexpr auto udp_reply_data = " Well hello friends! " sv ;
TEST_CASE ( udp_socket_read_write )
{
// NOTE: This is required here because Core::UDPServer requires
// Core::EventLoop through Core::Notifier.
Core : : EventLoop event_loop ;
auto udp_server = Core : : UDPServer : : construct ( ) ;
EXPECT ( udp_server - > bind ( { 127 , 0 , 0 , 1 } , 9090 ) ) ;
2023-05-07 18:14:06 +00:00
auto client_socket = TRY_OR_FAIL ( Core : : UDPSocket : : connect ( { { 127 , 0 , 0 , 1 } , 9090 } ) ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > is_open ( ) ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( client_socket - > write_until_depleted ( { sent_data . characters_without_null_termination ( ) , sent_data . length ( ) } ) ) ;
2021-09-10 22:46:52 +00:00
// FIXME: UDPServer::receive sadly doesn't give us a way to block on it,
// currently.
usleep ( 100000 ) ;
struct sockaddr_in client_address ;
2023-05-07 18:14:06 +00:00
auto server_receive_buffer = TRY_OR_FAIL ( udp_server - > receive ( 64 , client_address ) ) ;
2021-09-10 22:46:52 +00:00
EXPECT ( ! server_receive_buffer . is_empty ( ) ) ;
StringView server_received_data { server_receive_buffer . bytes ( ) } ;
EXPECT_EQ ( server_received_data , sent_data ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( udp_server - > send ( { udp_reply_data . characters_without_null_termination ( ) , udp_reply_data . length ( ) } , client_address ) ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > can_read_without_blocking ( 100 ) . release_value ( ) ) ;
EXPECT_EQ ( client_socket - > pending_bytes ( ) . release_value ( ) , udp_reply_data . length ( ) ) ;
2021-09-10 22:46:52 +00:00
// Testing that supplying a smaller buffer than required causes a failure.
auto small_buffer = ByteBuffer : : create_uninitialized ( 8 ) . release_value ( ) ;
2023-02-24 21:38:01 +00:00
EXPECT_EQ ( client_socket - > read_some ( small_buffer ) . error ( ) . code ( ) , EMSGSIZE ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto client_receive_buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( 64 ) ) ;
auto read_bytes = TRY_OR_FAIL ( client_socket - > read_some ( client_receive_buffer ) ) ;
2021-09-10 22:46:52 +00:00
2022-04-15 12:33:02 +00:00
StringView client_received_data { read_bytes } ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( udp_reply_data , client_received_data ) ;
}
// LocalSocket tests
TEST_CASE ( local_socket_read )
{
Core : : EventLoop event_loop ;
auto local_server = Core : : LocalServer : : construct ( ) ;
EXPECT ( local_server - > listen ( " /tmp/test-socket " ) ) ;
2023-02-08 22:05:44 +00:00
local_server - > on_accept = [ & ] ( NonnullOwnPtr < Core : : LocalSocket > server_socket ) {
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( server_socket - > write_some ( sent_data . bytes ( ) ) ) ;
2021-09-10 22:46:52 +00:00
event_loop . quit ( 0 ) ;
event_loop . pump ( ) ;
} ;
// NOTE: Doing this on another thread, because otherwise we're at an
// impasse. LocalSocket::connect blocks because there's nobody to
// accept, and LocalServer::accept blocks because there's nobody
// connected.
auto background_action = Threading : : BackgroundAction < int > : : construct (
[ ] ( auto & ) {
2022-01-02 13:52:38 +00:00
Core : : EventLoop event_loop ;
2023-05-07 18:14:06 +00:00
auto client_socket = MUST ( Core : : LocalSocket : : connect ( " /tmp/test-socket " ) ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > is_open ( ) ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > can_read_without_blocking ( 100 ) . release_value ( ) ) ;
EXPECT_EQ ( client_socket - > pending_bytes ( ) . release_value ( ) , sent_data . length ( ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto receive_buffer = MUST ( ByteBuffer : : create_uninitialized ( 64 ) ) ;
auto read_bytes = MUST ( client_socket - > read_some ( receive_buffer ) ) ;
2021-09-10 22:46:52 +00:00
2022-04-15 12:33:02 +00:00
StringView received_data { read_bytes } ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( sent_data , received_data ) ;
return 0 ;
} ,
2021-12-27 23:59:15 +00:00
nullptr ) ;
2021-09-10 22:46:52 +00:00
event_loop . exec ( ) ;
: : unlink ( " /tmp/test-socket " ) ;
}
TEST_CASE ( local_socket_write )
{
Core : : EventLoop event_loop ;
auto local_server = Core : : LocalServer : : construct ( ) ;
EXPECT ( local_server - > listen ( " /tmp/test-socket " ) ) ;
2023-02-08 22:05:44 +00:00
local_server - > on_accept = [ & ] ( NonnullOwnPtr < Core : : LocalSocket > server_socket ) {
2021-09-10 22:46:52 +00:00
// NOTE: For some reason LocalServer gives us a nonblocking socket..?
2022-01-14 13:12:49 +00:00
MUST ( server_socket - > set_blocking ( true ) ) ;
2021-09-10 22:46:52 +00:00
2022-01-18 13:33:40 +00:00
EXPECT ( MUST ( server_socket - > can_read_without_blocking ( 100 ) ) ) ;
2022-01-14 13:12:49 +00:00
auto pending_bytes = MUST ( server_socket - > pending_bytes ( ) ) ;
2023-05-07 18:14:06 +00:00
auto receive_buffer = TRY_OR_FAIL ( ByteBuffer : : create_uninitialized ( pending_bytes ) ) ;
auto read_bytes = TRY_OR_FAIL ( server_socket - > read_some ( receive_buffer ) ) ;
EXPECT_EQ ( read_bytes . size ( ) , sent_data . length ( ) ) ;
StringView received_data { read_bytes } ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( sent_data , received_data ) ;
event_loop . quit ( 0 ) ;
event_loop . pump ( ) ;
} ;
// NOTE: Same reason as in the local_socket_read test.
auto background_action = Threading : : BackgroundAction < int > : : construct (
[ ] ( auto & ) {
2023-05-07 18:14:06 +00:00
auto client_socket = MUST ( Core : : LocalSocket : : connect ( " /tmp/test-socket " ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
MUST ( client_socket - > write_until_depleted ( { sent_data . characters_without_null_termination ( ) , sent_data . length ( ) } ) ) ;
2021-12-29 22:31:45 +00:00
client_socket - > close ( ) ;
2021-09-10 22:46:52 +00:00
return 0 ;
} ,
2021-12-27 23:59:15 +00:00
nullptr ) ;
2021-09-10 22:46:52 +00:00
event_loop . exec ( ) ;
: : unlink ( " /tmp/test-socket " ) ;
}
// Buffered stream tests
2021-12-31 20:36:37 +00:00
TEST_CASE ( buffered_long_file_read )
2021-09-10 22:46:52 +00:00
{
2023-05-07 18:14:06 +00:00
auto raw_file = TRY_OR_FAIL ( Core : : File : : open ( " /usr/Tests/LibCore/long_lines.txt " sv , Core : : File : : OpenMode : : Read ) ) ;
auto file = TRY_OR_FAIL ( Core : : InputBufferedFile : : create ( move ( raw_file ) ) ) ;
2021-09-10 22:46:52 +00:00
auto buffer = ByteBuffer : : create_uninitialized ( 4096 ) . release_value ( ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > seek ( 255 , SeekMode : : SetPosition ) ) ;
2021-12-29 22:31:45 +00:00
EXPECT ( file - > can_read_line ( ) . release_value ( ) ) ;
2023-05-07 18:14:06 +00:00
auto line = TRY_OR_FAIL ( file - > read_line ( buffer ) ) ;
EXPECT_EQ ( line . length ( ) , 4095ul ) ; // 4095 bytes on the third line
2021-09-10 22:46:52 +00:00
// Testing that buffering with seeking works properly
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file - > seek ( 365 , SeekMode : : SetPosition ) ) ;
auto after_seek_line = TRY_OR_FAIL ( file - > read_line ( buffer ) ) ;
EXPECT_EQ ( after_seek_line . length ( ) , 3985ul ) ; // 4095 - 110
2021-09-10 22:46:52 +00:00
}
2021-12-31 20:36:37 +00:00
TEST_CASE ( buffered_small_file_read )
{
2023-05-07 18:14:06 +00:00
auto raw_file = TRY_OR_FAIL ( Core : : File : : open ( " /usr/Tests/LibCore/small.txt " sv , Core : : File : : OpenMode : : Read ) ) ;
auto file = TRY_OR_FAIL ( Core : : InputBufferedFile : : create ( move ( raw_file ) ) ) ;
2021-12-31 20:36:37 +00:00
static constexpr StringView expected_lines [ ] {
" Well " sv ,
" hello " sv ,
" friends! " sv ,
" :^) " sv
} ;
// Testing that we don't read out of bounds when the entire file fits into the buffer
auto buffer = ByteBuffer : : create_uninitialized ( 4096 ) . release_value ( ) ;
for ( auto const & line : expected_lines ) {
2021-12-29 22:31:45 +00:00
VERIFY ( file - > can_read_line ( ) . release_value ( ) ) ;
2023-05-07 18:14:06 +00:00
auto read_line = TRY_OR_FAIL ( file - > read_line ( buffer ) ) ;
EXPECT_EQ ( read_line . length ( ) , line . length ( ) ) ;
EXPECT_EQ ( StringView ( buffer . span ( ) . trim ( read_line . length ( ) ) ) , line ) ;
2021-12-31 20:36:37 +00:00
}
2023-05-07 18:14:06 +00:00
bool can_read_line = TRY_OR_FAIL ( file - > can_read_line ( ) ) ;
EXPECT ( ! can_read_line ) ;
2021-12-31 20:36:37 +00:00
}
2023-01-16 14:46:59 +00:00
TEST_CASE ( buffered_file_tell_and_seek )
{
2023-01-16 15:46:18 +00:00
// We choose a buffer size of 12 bytes to cover half of the input file.
2023-02-09 02:02:46 +00:00
auto file = Core : : File : : open ( " /usr/Tests/LibCore/small.txt " sv , Core : : File : : OpenMode : : Read ) . release_value ( ) ;
2023-05-03 22:45:18 +00:00
auto buffered_file = Core : : InputBufferedFile : : create ( move ( file ) , 12 ) . release_value ( ) ;
2023-01-16 14:46:59 +00:00
// Initial state.
{
auto current_offset = buffered_file - > tell ( ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 0ul ) ;
2023-01-16 14:46:59 +00:00
}
// Read a character.
{
auto character = buffered_file - > read_value < char > ( ) . release_value ( ) ;
EXPECT_EQ ( character , ' W ' ) ;
auto current_offset = buffered_file - > tell ( ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 1ul ) ;
2023-01-16 14:46:59 +00:00
}
// Read one more character.
{
auto character = buffered_file - > read_value < char > ( ) . release_value ( ) ;
EXPECT_EQ ( character , ' e ' ) ;
auto current_offset = buffered_file - > tell ( ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 2ul ) ;
2023-01-16 14:46:59 +00:00
}
// Seek seven characters forward.
{
2023-01-22 04:09:11 +00:00
auto current_offset = buffered_file - > seek ( 7 , SeekMode : : FromCurrentPosition ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 9ul ) ;
2023-01-16 14:46:59 +00:00
}
// Read a character again.
{
auto character = buffered_file - > read_value < char > ( ) . release_value ( ) ;
EXPECT_EQ ( character , ' o ' ) ;
auto current_offset = buffered_file - > tell ( ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 10ul ) ;
2023-01-16 14:46:59 +00:00
}
// Seek five characters backwards.
{
2023-01-22 04:09:11 +00:00
auto current_offset = buffered_file - > seek ( - 5 , SeekMode : : FromCurrentPosition ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 5ul ) ;
2023-01-16 14:46:59 +00:00
}
// Read a character.
{
auto character = buffered_file - > read_value < char > ( ) . release_value ( ) ;
EXPECT_EQ ( character , ' h ' ) ;
auto current_offset = buffered_file - > tell ( ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 6ul ) ;
2023-01-16 14:46:59 +00:00
}
// Seek back to the beginning.
{
2023-01-22 04:09:11 +00:00
auto current_offset = buffered_file - > seek ( 0 , SeekMode : : SetPosition ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 0ul ) ;
2023-01-16 14:46:59 +00:00
}
2023-01-16 15:46:18 +00:00
// Read the first character. This should prime the buffer if it hasn't happened already.
2023-01-16 14:46:59 +00:00
{
auto character = buffered_file - > read_value < char > ( ) . release_value ( ) ;
EXPECT_EQ ( character , ' W ' ) ;
auto current_offset = buffered_file - > tell ( ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 1ul ) ;
2023-01-16 14:46:59 +00:00
}
2023-01-16 15:46:18 +00:00
// Seek beyond the buffer size, which should invalidate the buffer.
{
2023-01-22 04:09:11 +00:00
auto current_offset = buffered_file - > seek ( 12 , SeekMode : : SetPosition ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 12ul ) ;
2023-01-16 15:46:18 +00:00
}
// Ensure that we still read the correct contents from the new offset with a (presumably) freshly filled buffer.
{
auto character = buffered_file - > read_value < char > ( ) . release_value ( ) ;
EXPECT_EQ ( character , ' r ' ) ;
auto current_offset = buffered_file - > tell ( ) . release_value ( ) ;
2023-01-17 13:52:46 +00:00
EXPECT_EQ ( current_offset , 13ul ) ;
2023-01-16 15:46:18 +00:00
}
2023-01-16 14:46:59 +00:00
}
2023-03-16 16:46:21 +00:00
constexpr auto new_newlines_message = " Hi, look, no newlines " sv ;
TEST_CASE ( buffered_file_without_newlines )
{
constexpr auto filename = " /tmp/file-without-newlines " sv ;
auto file_wo_newlines = Core : : File : : open ( filename , Core : : File : : OpenMode : : Write ) . release_value ( ) ;
2023-05-07 18:14:06 +00:00
TRY_OR_FAIL ( file_wo_newlines - > write_until_depleted ( new_newlines_message . bytes ( ) ) ) ;
2023-03-16 16:46:21 +00:00
file_wo_newlines - > close ( ) ;
2023-05-03 22:45:18 +00:00
auto ro_file = Core : : InputBufferedFile : : create ( Core : : File : : open ( filename , Core : : File : : OpenMode : : Read ) . release_value ( ) , new_newlines_message . length ( ) + 1 ) . release_value ( ) ;
2023-03-16 16:46:21 +00:00
2023-05-07 18:14:06 +00:00
auto can_read_line = TRY_OR_FAIL ( ro_file - > can_read_line ( ) ) ;
EXPECT ( can_read_line ) ;
2024-01-20 12:50:48 +00:00
auto can_read_up_to_newline = TRY_OR_FAIL ( ro_file - > can_read_up_to_delimiter ( " \n " sv . bytes ( ) ) ) ;
EXPECT ( ! can_read_up_to_newline ) ;
2023-03-16 16:46:21 +00:00
Array < u8 , new_newlines_message . length ( ) + 1 > buffer ;
EXPECT ( ro_file - > read_line ( buffer ) . release_value ( ) = = new_newlines_message ) ;
}
2021-09-10 22:46:52 +00:00
constexpr auto buffered_sent_data = " Well hello friends! \n :^) \n This shouldn't be present. :^( " sv ;
constexpr auto first_line = " Well hello friends! " sv ;
constexpr auto second_line = " :^) " sv ;
TEST_CASE ( buffered_tcp_socket_read )
{
Core : : EventLoop event_loop ;
2023-05-07 18:14:06 +00:00
auto tcp_server = TRY_OR_FAIL ( Core : : TCPServer : : try_create ( ) ) ;
TRY_OR_FAIL ( tcp_server - > listen ( { 127 , 0 , 0 , 1 } , 9090 ) ) ;
TRY_OR_FAIL ( tcp_server - > set_blocking ( true ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto unbuffered_socket = TRY_OR_FAIL ( Core : : TCPSocket : : connect ( { { 127 , 0 , 0 , 1 } , 9090 } ) ) ;
auto client_socket = TRY_OR_FAIL ( Core : : BufferedTCPSocket : : create ( move ( unbuffered_socket ) ) ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > is_open ( ) ) ;
2021-09-10 22:46:52 +00:00
2023-05-07 18:14:06 +00:00
auto server_socket = TRY_OR_FAIL ( tcp_server - > accept ( ) ) ;
TRY_OR_FAIL ( server_socket - > write_some ( { buffered_sent_data . characters_without_null_termination ( ) , sent_data . length ( ) } ) ) ;
2021-09-10 22:46:52 +00:00
2021-12-29 22:31:45 +00:00
EXPECT ( client_socket - > can_read_without_blocking ( 100 ) . release_value ( ) ) ;
2021-09-10 22:46:52 +00:00
auto receive_buffer = ByteBuffer : : create_uninitialized ( 64 ) . release_value ( ) ;
2023-05-07 18:14:06 +00:00
auto first_received_line = TRY_OR_FAIL ( client_socket - > read_line ( receive_buffer ) ) ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( first_received_line , first_line ) ;
2023-05-07 18:14:06 +00:00
auto second_received_line = TRY_OR_FAIL ( client_socket - > read_line ( receive_buffer ) ) ;
2021-09-10 22:46:52 +00:00
EXPECT_EQ ( second_received_line , second_line ) ;
}