class TestCase::Sys::Select {
  use Sys;
  use Sys::Select;
  use Sys::Select::Fd_set;
  use Sys::Select::Constant as SELECT;
  
  use Sys::Socket;
  use Sys::Socket::Constant as SOCKET;
  use Sys::Socket::Sockaddr;
  use Sys::Socket::Sockaddr::In;
  use Sys::Process;
  
  use Fn;
  
  static method select : int ($port : int) {
    {
      # Socket
      my $no0_socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);

      unless ($no0_socket > 0) {
        return 0;
      }
      
      Fn->defer([$no0_socket : int] method :void () {
        Sys::Socket->close($no0_socket);
      });
      
      # IPv4 address
      my $no0_address = Sys::Socket::Sockaddr::In->new;
      $no0_address->set_sin_family((byte)SOCKET->AF_INET);
      $no0_address->set_sin_port(Sys::Socket->htons((short)$port));
      my $no0_sin_addr = $no0_address->sin_addr;
      Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $no0_sin_addr);
      $no0_address->set_sin_addr($no0_sin_addr);
      
      my $no0_status_connect = Sys::Socket->connect($no0_socket, $no0_address, $no0_address->size);
      
      unless ($no0_status_connect == 0) {
        Sys::Socket->close($no0_socket);
        return 0;
      }

      # Socket
      my $no1_socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);

      unless ($no1_socket > 0) {
        return 0;
      }
      
      Fn->defer([$no1_socket : int] method :void () {
        Sys::Socket->close($no1_socket);
      });
      
      # IPv4 address
      my $no1_address = Sys::Socket::Sockaddr::In->new;
      $no1_address->set_sin_family((byte)SOCKET->AF_INET);
      $no1_address->set_sin_port(Sys::Socket->htons((short)$port));
      my $no1_sin_addr = $no1_address->sin_addr;
      Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $no1_sin_addr);
      $no1_address->set_sin_addr($no1_sin_addr);
      
      my $no1_status_connect = Sys::Socket->connect($no1_socket, $no1_address, $no1_address->size);
      
      unless ($no1_status_connect == 0) {
        Sys::Socket->close($no1_socket);
        return 0;
      }
      
      {
        my $writefds = Sys::Select::Fd_set->new;
        
        Sys::Select->FD_SET($no0_socket, $writefds);
        Sys::Select->FD_SET($no1_socket, $writefds);
        
        my $socket_max = 0;
        if ($no0_socket > $no1_socket) {
          $socket_max = $no0_socket;
        }
        else {
          $socket_max = $no1_socket;
        }
        
        my $timeout = 10;
        
        my $ready_count_out = Sys->select(undef, $writefds, undef, $timeout);
        
        unless ($ready_count_out == 2) {
          return 0;
        }
        
        unless (Sys::Select->FD_ISSET($no0_socket, $writefds)) {
          return 0;
        }
        unless (Sys::Select->FD_ISSET($no1_socket, $writefds)) {
          return 0;
        }
      }
      
      {
        my $no0_send_buffer = "abcd";
        
        my $no0_send_length = Sys::Socket->send($no0_socket, $no0_send_buffer, length $no0_send_buffer, 0);
        
        unless ($no0_send_length == 4) {
          return 0;
        }
      }
      
      {
        my $no0_send_buffer = "ef";
        
        my $no0_send_length = Sys::Socket->send($no0_socket, $no0_send_buffer, length $no0_send_buffer, 0);
        
        unless ($no0_send_length == 2) {
          return 0;
        }
      }
      
      my $no0_status_shutdown = Sys::Socket->shutdown($no0_socket, SOCKET->SHUT_WR);
      
      unless ($no0_status_shutdown == 0) {
        return 0;
      }

      {
        my $no1_send_buffer = "abcd";
        
        my $no1_send_length = Sys::Socket->send($no1_socket, $no1_send_buffer, length $no1_send_buffer, 0);
        
        unless ($no1_send_length == 4) {
          return 0;
        }
      }
      
      {
        my $no1_send_buffer = "ef";
        
        my $no1_send_length = Sys::Socket->send($no1_socket, $no1_send_buffer, length $no1_send_buffer, 0);
        
        unless ($no1_send_length == 2) {
          return 0;
        }
      }
      
      my $no1_status_shutdown = Sys::Socket->shutdown($no1_socket, SOCKET->SHUT_WR);
      
      unless ($no1_status_shutdown == 0) {
        return 0;
      }
      
      # Wait a little for the server
      Sys::Process->sleep(1);
      
      {
        my $readfds = Sys::Select::Fd_set->new;
        
        Sys::Select->FD_SET($no0_socket, $readfds);
        Sys::Select->FD_SET($no1_socket, $readfds);
        
        my $socket_max = 0;
        if ($no0_socket > $no1_socket) {
          $socket_max = $no0_socket;
        }
        else {
          $socket_max = $no1_socket;
        }
        
        my $timeout = 10;
        
        my $ready_count_out = Sys->select($readfds, undef, undef, $timeout);
        
        unless ($ready_count_out == 2) {
          return 0;
        }
        
        unless (Sys::Select->FD_ISSET($no0_socket, $readfds)) {
          return 0;
        }
        unless (Sys::Select->FD_ISSET($no1_socket, $readfds)) {
          return 0;
        }
      }
      
      {
        my $no0_recv_buffer = (mutable string)new_string_len 3;
        my $no0_recv_length = Sys::Socket->recv($no0_socket, $no0_recv_buffer, length $no0_recv_buffer, 0);
        
        unless ($no0_recv_length == 3) {
          return 0;
        }
        
        unless ($no0_recv_buffer eq "abc") {
          return 0;
        }
      }
      
      {
        my $no0_recv_buffer = (mutable string)new_string_len 3;
        my $no0_recv_length = Sys::Socket->recv($no0_socket, $no0_recv_buffer, length $no0_recv_buffer, 0);
        
        unless ($no0_recv_length == 3) {
          return 0;
        }
        
        unless ($no0_recv_buffer eq "def") {
          return 0;
        }
      }

      {
        my $no0_recv_buffer = (mutable string)new_string_len 3;
        my $no0_recv_length = Sys::Socket->recv($no0_socket, $no0_recv_buffer, length $no0_recv_buffer, 0);
        
        unless ($no0_recv_length == 0) {
          return 0;
        }
      }
      
      {
        my $no1_recv_buffer = (mutable string)new_string_len 3;
        my $no1_recv_length = Sys::Socket->recv($no1_socket, $no1_recv_buffer, length $no1_recv_buffer, 0);
        
        unless ($no1_recv_length == 3) {
          return 0;
        }
        
        unless ($no1_recv_buffer eq "abc") {
          return 0;
        }
      }
      
      {
        my $no1_recv_buffer = (mutable string)new_string_len 3;
        my $no1_recv_length = Sys::Socket->recv($no1_socket, $no1_recv_buffer, length $no1_recv_buffer, 0);
        
        unless ($no1_recv_length == 3) {
          return 0;
        }
        
        unless ($no1_recv_buffer eq "def") {
          return 0;
        }
      }

      {
        my $no1_recv_buffer = (mutable string)new_string_len 3;
        my $no1_recv_length = Sys::Socket->recv($no1_socket, $no1_recv_buffer, length $no1_recv_buffer, 0);
        
        unless ($no1_recv_length == 0) {
          return 0;
        }
      }
    }
    
    return 1;
  }

  static method select_utils : int () {

    {
      my $set = Sys::Select::Fd_set->new;
    
      my $fd = 0;
      
      if (Sys::Select->FD_ISSET($fd, $set)) {
        return 0;
      }
      
      Sys::Select->FD_SET($fd, $set);
      
      unless (Sys::Select->FD_ISSET($fd, $set)) {
        return 0;
      }
      
      Sys::Select->FD_CLR($fd, $set);
      
      if (Sys::Select->FD_ISSET($fd, $set)) {
        return 0;
      }
    }

    {
      my $set = Sys::Select::Fd_set->new;
      my $fd = SELECT->FD_SETSIZE - 1;
      
      if (Sys::Select->FD_ISSET($fd, $set)) {
        return 0;
      }
      
      Sys::Select->FD_SET($fd, $set);
      
      unless (Sys::Select->FD_ISSET($fd, $set)) {
        return 0;
      }
      
      Sys::Select->FD_CLR($fd, $set);
      
      if (Sys::Select->FD_ISSET($fd, $set)) {
        return 0;
      }
    }
    
    {
      my $set = Sys::Select::Fd_set->new;
      Sys::Select->FD_SET(0, $set);
      Sys::Select->FD_SET(1, $set);
      Sys::Select->FD_SET(2, $set);
      
      Sys::Select->FD_ZERO($set);
      
      if (Sys::Select->FD_ISSET(0, $set)) {
        return 0;
      }
      if (Sys::Select->FD_ISSET(1, $set)) {
        return 0;
      }
      if (Sys::Select->FD_ISSET(2, $set)) {
        return 0;
      }
    }
    
    {
      my $set = Sys::Select::Fd_set->new;
      Sys::Select->FD_SET(0, $set);
      Sys::Select->FD_SET(1, $set);
      Sys::Select->FD_SET(2, $set);
      
      my $set_clone = $set->clone;
      
      unless (Sys::Select->FD_ISSET(0, $set_clone)) {
        return 0;
      }
      unless (Sys::Select->FD_ISSET(1, $set_clone)) {
        return 0;
      }
      unless (Sys::Select->FD_ISSET(2, $set_clone)) {
        return 0;
      }
    }
    
    return 1;
  }
}