@@ -3,4 +3,5 @@ | |||
#include <cppfs/config.h> | |||
#include <cppfs/directory.h> | |||
#include <cppfs/file.h> | |||
#include <cppfs/file_events.h> | |||
#include <cppfs/path.h> |
@@ -19,8 +19,6 @@ namespace cppfs | |||
static constexpr char path_delimiter = '/'; | |||
static constexpr const char * temp_dir = "/tmp"; | |||
}; | |||
using fd_handle = int; | |||
#endif | |||
} |
@@ -66,12 +66,6 @@ namespace cppfs | |||
#endif | |||
}; | |||
public: | |||
/** | |||
* @brief Get the default file permissions for directories. | |||
*/ | |||
static inline const file_permissions& default_permissions(); | |||
private: | |||
cppfs::path _path; | |||
@@ -97,7 +91,7 @@ namespace cppfs | |||
*/ | |||
inline const directory& create( | |||
bool p_parent, | |||
const file_permissions& p_perm = default_permissions()) const; | |||
const file_permissions& p_perm = file_permissions::defaults()) const; | |||
/** | |||
* @brief Remove the directory (and all it's content if the parameter is set to true) | |||
@@ -9,24 +9,6 @@ namespace cppfs | |||
/* directory */ | |||
const file_permissions& directory::default_permissions() | |||
{ | |||
static const file_permissions value({ | |||
file_permission::user_read, | |||
file_permission::user_write, | |||
file_permission::user_execute, | |||
file_permission::group_read, | |||
file_permission::group_write, | |||
file_permission::group_execute, | |||
file_permission::others_read, | |||
file_permission::others_execute, | |||
}); | |||
return value; | |||
} | |||
template<typename... T_args> | |||
directory::directory(T_args&&... p_args) | |||
: _path(std::forward<T_args>(p_args)...) | |||
@@ -2,13 +2,37 @@ | |||
#include <string> | |||
#include <cppcore/misc/flags.h> | |||
#include <cppfs/config.h> | |||
#include "../path.h" | |||
#include "../misc.h" | |||
namespace cppfs | |||
{ | |||
enum class access_mode | |||
{ | |||
unknown = 0, | |||
read_only, | |||
write_only, | |||
read_write, | |||
}; | |||
enum class open_flag | |||
{ | |||
unknown = 0, | |||
create, | |||
append, | |||
truncate, | |||
non_blocking, | |||
}; | |||
using open_flags = cppcore::shifted_flags<open_flag>; | |||
struct file | |||
: public raw_handle | |||
{ | |||
private: | |||
cppfs::path _path; | |||
@@ -20,6 +44,11 @@ namespace cppfs | |||
template<typename... T_args> | |||
inline file(T_args&&... p_args); | |||
/** | |||
* @brief Destrutor. | |||
*/ | |||
inline ~file(); | |||
/** | |||
* @brief Get the path of the file. | |||
*/ | |||
@@ -30,10 +59,42 @@ namespace cppfs | |||
*/ | |||
inline bool exists() const; | |||
/** | |||
* @brief Get the size of the file. | |||
*/ | |||
inline size_t size() const; | |||
/** | |||
* @brief Remove the file. | |||
*/ | |||
inline const file& remove() const; | |||
/** | |||
* @brief Open the file for reading or writing. | |||
*/ | |||
inline void open( | |||
const access_mode& p_access, | |||
const open_flags& p_flags = open_flags::empty(), | |||
const file_permissions& p_permissions = file_permissions::defaults()); | |||
/** | |||
* @brief Read data from the file and store it in the passed buffer. | |||
*/ | |||
inline size_t read( | |||
void * p_buffer, | |||
size_t p_count); | |||
/** | |||
* @brief Write data from the passed buffer to the file. | |||
*/ | |||
inline size_t write( | |||
const void * p_buffer, | |||
size_t p_count); | |||
/** | |||
* @brief Close the file. | |||
*/ | |||
inline void close(); | |||
}; | |||
} |
@@ -12,6 +12,9 @@ namespace cppfs | |||
: _path(std::forward<T_args>(p_args)...) | |||
{ } | |||
file::~file() | |||
{ close(); } | |||
const cppfs::path& file::path() const | |||
{ return _path; } | |||
@@ -1,5 +1,8 @@ | |||
#pragma once | |||
#include <fcntl.h> | |||
#include <sys/stat.h> | |||
#include "file.h" | |||
namespace cppfs | |||
@@ -7,6 +10,20 @@ namespace cppfs | |||
/* file */ | |||
size_t file::size() const | |||
{ | |||
struct stat st; | |||
auto& s = _path.str(); | |||
if (stat(s.c_str(), &st)) | |||
{ | |||
using namespace std::string_literals; | |||
throw cppcore::error_exception("Unable to get file size: "s + s, errno); | |||
} | |||
return cppcore::convert_cast<size_t>(st.st_size); | |||
} | |||
const file& file::remove() const | |||
{ | |||
using namespace std::string_literals; | |||
@@ -18,4 +35,89 @@ namespace cppfs | |||
return *this; | |||
} | |||
void file::open( | |||
const access_mode& p_access, | |||
const open_flags& p_flags, | |||
const file_permissions& p_permissions) | |||
{ | |||
close(); | |||
int flags = 0; | |||
switch (p_access) | |||
{ | |||
case access_mode::read_only: | |||
flags |= O_RDONLY; | |||
break; | |||
case access_mode::write_only: | |||
flags |= O_WRONLY; | |||
break; | |||
case access_mode::read_write: | |||
flags |= O_RDWR; | |||
break; | |||
case access_mode::unknown: | |||
throw cppcore::exception("Invalid access mode: unknown"); | |||
} | |||
if (p_flags.is_set(open_flag::create)) flags |= O_CREAT; | |||
if (p_flags.is_set(open_flag::append)) flags |= O_APPEND; | |||
if (p_flags.is_set(open_flag::truncate)) flags |= O_TRUNC; | |||
if (p_flags.is_set(open_flag::non_blocking)) flags |= O_NONBLOCK; | |||
auto& s = _path.str(); | |||
_handle = ::open(s.c_str(), flags, file_permissions::to_unix(p_permissions)); | |||
if (_handle < 0) | |||
{ | |||
using namespace std::string_literals; | |||
throw cppcore::error_exception("Unable to open file: "s + s, errno); | |||
} | |||
} | |||
size_t file::read( | |||
void * p_buffer, | |||
size_t p_count) | |||
{ | |||
if (_handle < 0) | |||
open(access_mode::read_only, open_flags::empty(), file_permissions::defaults()); | |||
ssize_t ret = ::read(_handle, p_buffer, p_count); | |||
if (ret < 0) | |||
{ | |||
using namespace std::string_literals; | |||
throw cppcore::error_exception("Unable to read from file: "s + _path.str(), errno); | |||
} | |||
return static_cast<size_t>(ret); | |||
} | |||
size_t file::write( | |||
const void * p_buffer, | |||
size_t p_count) | |||
{ | |||
if (_handle < 0) | |||
open(access_mode::write_only, open_flag::append, file_permissions::defaults()); | |||
ssize_t ret = ::write(_handle, p_buffer, p_count); | |||
if (ret < 0) | |||
{ | |||
using namespace std::string_literals; | |||
throw cppcore::error_exception("Unable to write to file: "s + _path.str(), errno); | |||
} | |||
return static_cast<size_t>(ret); | |||
} | |||
void file::close() | |||
{ | |||
if (_handle >= 0) | |||
{ | |||
if (::close(_handle)) | |||
{ | |||
using namespace std::string_literals; | |||
throw cppcore::error_exception("Unable to close file: "s + _path.str(), errno); | |||
} | |||
_handle = -1; | |||
} | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
#pragma once | |||
#include <cppfs/config.h> | |||
#include "file_events/file_events.h" | |||
#if cppfs_os == cppfs_os_linux | |||
#include "file_events/select.h" | |||
#endif | |||
#include "file_events/file_events.inl" | |||
#if cppfs_os == cppfs_os_linux | |||
#include "file_events/select.inl" | |||
#endif |
@@ -0,0 +1,59 @@ | |||
#pragma once | |||
#include <sys/select.h> | |||
namespace cppfs | |||
{ | |||
struct fdset final | |||
: public fd_set | |||
{ | |||
public: | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
inline fdset(); | |||
/** | |||
* @brief Check if any file descriptor is set in this set. | |||
* | |||
* @param[in] max_fd Largest file descriptor stored. | |||
* | |||
* @retval true If any file descriptor is set. | |||
* @retval false If no file descriptor is set. | |||
*/ | |||
inline bool is_any(int max_fd) const; | |||
/** | |||
* @brief Check if the passed file descriptor is set in this set. | |||
* | |||
* @param[in] fd File descriptor to check for. | |||
* | |||
* @retval true If the passed file descriptor is set. | |||
* @retval false If the passed file descriptor is not set. | |||
*/ | |||
inline bool is_set(int fd) const; | |||
/** | |||
* @brief Set the passed file descriptor in the set. | |||
* | |||
* @param[in] fd File descriptor to set. | |||
*/ | |||
inline void set(int fd); | |||
/** | |||
* @brief Clear the passed file descriptor in the set. | |||
* | |||
* @param[in] fd File descriptor to clear. | |||
*/ | |||
inline void clear(int fd); | |||
/** | |||
* @brief Clear the complete file descriptor set. | |||
*/ | |||
inline void reset(); | |||
}; | |||
} | |||
#include "fdset.inl" |
@@ -0,0 +1,63 @@ | |||
#pragma once | |||
#include "fdset.h" | |||
namespace cppfs | |||
{ | |||
/* fdset */ | |||
static_assert( | |||
sizeof(fd_set) == sizeof(fdset), | |||
"Size of fd set implementation does not match."); | |||
fdset::fdset() | |||
{ | |||
FD_ZERO(this); | |||
} | |||
bool fdset::is_any(int max_fd) const | |||
{ | |||
static constexpr int field_count = sizeof(fds_bits) / sizeof(fds_bits[0]); | |||
if (max_fd >= FD_SETSIZE) | |||
throw cppcore::exception("Size of fd set exceeded!"); | |||
if (max_fd < 0) | |||
return false; | |||
auto cnt = (max_fd / field_count) + 1; | |||
for (int i = 0; i < cnt; ++i) | |||
{ | |||
if (fds_bits[i]) | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool fdset::is_set(int fd) const | |||
{ | |||
if (fd >= FD_SETSIZE) | |||
throw cppcore::exception("Size of fd set exceeded!"); | |||
return FD_ISSET(fd, this); | |||
} | |||
void fdset::set(int fd) | |||
{ | |||
if (fd >= FD_SETSIZE) | |||
throw cppcore::exception("Size of fd set exceeded!"); | |||
FD_SET(fd, this); | |||
} | |||
void fdset::clear(int fd) | |||
{ | |||
if (fd >= FD_SETSIZE) | |||
throw cppcore::exception("Size of fd set exceeded!"); | |||
FD_CLR(fd, this); | |||
} | |||
void fdset::reset() | |||
{ FD_ZERO(this); } | |||
} |
@@ -0,0 +1,96 @@ | |||
#pragma once | |||
#include <cppfs/misc.h> | |||
#include "types.h" | |||
namespace cppfs | |||
{ | |||
template<typename T_impl> | |||
struct file_events | |||
{ | |||
public: | |||
using impl_type = T_impl; | |||
using result_impl_type = typename impl_type::result_type; | |||
struct result | |||
{ | |||
private: | |||
result_impl_type _impl; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
template<typename X_impl> | |||
inline result(X_impl&& p_impl); | |||
/** | |||
* @brief Check if any event has occured in any handle. | |||
*/ | |||
bool is_set() const; | |||
/** | |||
* @brief Check if any event has occured in the passed handle. | |||
*/ | |||
bool is_set( | |||
const raw_handle& p_handle) const; | |||
/** | |||
* @brief Check if any of the passed event has occured in any handle. | |||
*/ | |||
bool is_set( | |||
const event_types& p_events) const; | |||
/** | |||
* @brief Check if any of the passed event has occured in the passed handle. | |||
*/ | |||
bool is_set( | |||
const event_types& p_events, | |||
const raw_handle& p_handle) const; | |||
}; | |||
private: | |||
impl_type _impl; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
inline file_events(); | |||
/** | |||
* @brief Add or change a event listener for the passed file. | |||
*/ | |||
inline void add( | |||
const raw_handle& p_handle, | |||
const event_types& p_events); | |||
/** | |||
* @brief Remove the event listener for the passed file. | |||
*/ | |||
inline void erase( | |||
const raw_handle& p_handle); | |||
/** | |||
* @brief Reset all event listeners. | |||
*/ | |||
inline void reset(); | |||
/** | |||
* @brief Wait for file events and return the result. | |||
*/ | |||
inline result wait( | |||
const event_timeout * p_timeout) const; | |||
/** | |||
* @brief Wait for file events and call the passed callback for each event. | |||
*/ | |||
template<typename T_lambda> | |||
inline void wait( | |||
T_lambda&& p_lambda, | |||
const event_timeout * p_timeout) const; | |||
}; | |||
} |
@@ -0,0 +1,89 @@ | |||
#pragma once | |||
#include "file_events.h" | |||
namespace cppfs | |||
{ | |||
/* file_events::result */ | |||
template<typename T_impl> | |||
template<typename X_impl> | |||
file_events<T_impl>::result::result(X_impl&& p_impl) | |||
: _impl(std::forward<X_impl>(p_impl)) | |||
{ } | |||
template<typename T_impl> | |||
bool file_events<T_impl>::result::is_set() const | |||
{ | |||
static const event_types all_types({ | |||
event_type::read, | |||
event_type::write, | |||
event_type::except, | |||
}); | |||
return _impl.is_set(all_types, nullptr); | |||
} | |||
template<typename T_impl> | |||
bool file_events<T_impl>::result::is_set( | |||
const raw_handle& p_handle) const | |||
{ | |||
static const event_types all_types({ | |||
event_type::read, | |||
event_type::write, | |||
event_type::except, | |||
}); | |||
return _impl.is_set(all_types, &p_handle); | |||
} | |||
template<typename T_impl> | |||
bool file_events<T_impl>::result::is_set( | |||
const event_types& p_events) const | |||
{ | |||
return _impl.is_set(p_events, nullptr); | |||
} | |||
template<typename T_impl> | |||
bool file_events<T_impl>::result::is_set( | |||
const event_types& p_events, | |||
const raw_handle& p_handle) const | |||
{ | |||
return _impl.is_set(p_events, &p_handle); | |||
} | |||
/* file_events */ | |||
template<typename T_impl> | |||
file_events<T_impl>::file_events() | |||
: _impl() | |||
{ } | |||
template<typename T_impl> | |||
void file_events<T_impl>::add( | |||
const raw_handle& p_handle, | |||
const event_types& p_events) | |||
{ _impl.add(p_handle, p_events); } | |||
template<typename T_impl> | |||
void file_events<T_impl>::erase( | |||
const raw_handle& p_handle) | |||
{ _impl.erase(p_handle); } | |||
template<typename T_impl> | |||
void file_events<T_impl>::reset() | |||
{ _impl = impl_type(); } | |||
template<typename T_impl> | |||
typename file_events<T_impl>::result | |||
file_events<T_impl>::wait( | |||
const event_timeout * p_timeout) const | |||
{ return result(_impl.wait(p_timeout)); } | |||
template<typename T_impl> | |||
template<typename T_lambda> | |||
void file_events<T_impl>::wait( | |||
T_lambda&& p_lambda, | |||
const event_timeout * p_timeout) const | |||
{ _impl.wait(std::forward<T_lambda>(p_lambda), p_timeout); } | |||
} |
@@ -0,0 +1,68 @@ | |||
#pragma once | |||
#include <sys/select.h> | |||
#include <cppfs/file/file.h> | |||
#include "types.h" | |||
#include "fdset.h" | |||
namespace cppfs | |||
{ | |||
struct fe_select | |||
{ | |||
public: | |||
struct storage | |||
{ | |||
int max_fd { -1 }; | |||
fdset read; | |||
fdset write; | |||
fdset except; | |||
inline bool is_set( | |||
const event_types& p_events, | |||
const raw_handle* p_handle) const; | |||
}; | |||
using result_type = storage; | |||
private: | |||
storage _storage; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
inline fe_select() = default; | |||
public: /* file_events implementation */ | |||
/** | |||
* @brief Add or change a event listener for the passed file. | |||
*/ | |||
inline void add( | |||
const raw_handle& p_handle, | |||
const event_types& p_events); | |||
/** | |||
* @brief Remove the event listener for the passed handle. | |||
*/ | |||
inline void erase( | |||
const raw_handle& p_handle); | |||
/** | |||
* @brief Wait for file events and return the result. | |||
*/ | |||
inline result_type wait( | |||
const event_timeout * p_timeout) const; | |||
/** | |||
* @brief Wait for file events and call the passed callback for each event. | |||
*/ | |||
template<typename T_lambda> | |||
inline void wait( | |||
T_lambda&& p_lambda, | |||
const event_timeout * p_timeout) const; | |||
}; | |||
} |
@@ -0,0 +1,114 @@ | |||
#pragma once | |||
#include <cppcore/conversion/time.h> | |||
#include "select.h" | |||
namespace cppfs | |||
{ | |||
/* fe_select::storage */ | |||
bool fe_select::storage::is_set( | |||
const event_types& p_events, | |||
const raw_handle* p_handle) const | |||
{ | |||
if (p_handle) | |||
{ | |||
auto fd = p_handle->handle(); | |||
return (p_events.is_set(event_type::read) && read.is_set(fd)) | |||
|| (p_events.is_set(event_type::write) && write.is_set(fd)) | |||
|| (p_events.is_set(event_type::except) && except.is_set(fd)); | |||
} | |||
else | |||
{ | |||
return (p_events.is_set(event_type::read) && read.is_any(max_fd)) | |||
|| (p_events.is_set(event_type::write) && write.is_any(max_fd)) | |||
|| (p_events.is_set(event_type::except) && except.is_any(max_fd)); | |||
} | |||
} | |||
/* fe_select */ | |||
void fe_select::add( | |||
const raw_handle& p_handle, | |||
const event_types& p_events) | |||
{ | |||
int fd = p_handle.handle(); | |||
if (fd < 0) | |||
throw cppcore::exception("The passed file is not opened!"); | |||
if (p_events.is_set(event_type::read)) _storage.read.set(fd); | |||
if (p_events.is_set(event_type::write)) _storage.write.set(fd); | |||
if (p_events.is_set(event_type::except)) _storage.except.set(fd); | |||
if ( !_storage.read.is_set(fd) | |||
&& !_storage.write.is_set(fd) | |||
&& !_storage.except.is_set(fd)) | |||
throw cppcore::exception("No or unkown events passed!"); | |||
_storage.max_fd = std::max(fd, _storage.max_fd); | |||
} | |||
void fe_select::erase(const raw_handle& p_handle) | |||
{ | |||
int fd = p_handle.handle(); | |||
if (fd < 0) | |||
throw cppcore::exception("The passed file is not opened!"); | |||
_storage.read.clear(fd); | |||
_storage.write.clear(fd); | |||
_storage.except.clear(fd); | |||
if (fd == _storage.max_fd) | |||
{ | |||
while (_storage.max_fd >= 0 | |||
&& !_storage.read.is_set(_storage.max_fd) | |||
&& !_storage.write.is_set(_storage.max_fd) | |||
&& !_storage.except.is_set(_storage.max_fd)) | |||
--_storage.max_fd; | |||
} | |||
} | |||
fe_select::result_type fe_select::wait(const event_timeout * p_timeout) const | |||
{ | |||
auto ret = _storage; | |||
struct timespec timeout { 0, 0 }; | |||
if (p_timeout) | |||
{ | |||
auto now = std::chrono::steady_clock::now(); | |||
if (now < *p_timeout) | |||
{ | |||
auto diff = *p_timeout - now; | |||
timeout = cppcore::duration_cast<timespec>(diff); | |||
} | |||
} | |||
if (::pselect(ret.max_fd + 1, &ret.read, &ret.write, &ret.except, p_timeout ? &timeout : nullptr, nullptr) < 0) | |||
{ | |||
auto err = errno; | |||
if (err != EINTR) | |||
throw cppcore::error_exception("Error while fetching file events with 'select'", err); | |||
} | |||
return ret; | |||
} | |||
template<typename T_lambda> | |||
void fe_select::wait(T_lambda&& p_lambda, const event_timeout * p_timeout) const | |||
{ | |||
auto ret = wait(p_timeout); | |||
for (auto fd = 0; fd <= ret.max_fd; ++fd) | |||
{ | |||
event_types ev; | |||
if (ret.read.is_set(fd)) ev.set(event_type::read); | |||
if (ret.write.is_set(fd)) ev.set(event_type::write); | |||
if (ret.except.is_set(fd)) ev.set(event_type::except); | |||
if (ev) | |||
p_lambda(fd, ev); | |||
} | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
#pragma once | |||
#include <chrono> | |||
#include <cppcore/misc/flags.h> | |||
namespace cppfs | |||
{ | |||
enum class event_type | |||
{ | |||
unknown = 0, | |||
read, | |||
write, | |||
except, | |||
}; | |||
using event_types = cppcore::shifted_flags<event_type>; | |||
using event_clock = std::chrono::steady_clock; | |||
using event_timeout = event_clock::time_point; | |||
} |
@@ -2,6 +2,8 @@ | |||
#include "misc/misc.h" | |||
#include "misc/misc.inl" | |||
#if cppfs_os == cppfs_os_linux | |||
#include "misc/misc.linux.inl" | |||
#endif |
@@ -2,10 +2,6 @@ | |||
#include <cppcore/misc/flags.h> | |||
#if cppfs_os == cppfs_os_linux | |||
#include <sys/stat.h> | |||
#endif | |||
namespace cppfs | |||
{ | |||
@@ -39,6 +35,20 @@ namespace cppfs | |||
others_execute, | |||
}; | |||
struct raw_handle | |||
{ | |||
#if cppfs_os == cppfs_os_linux | |||
protected: | |||
int _handle { -1 }; | |||
public: | |||
/** | |||
* @brief Get the raw handle. | |||
*/ | |||
inline int handle() const; | |||
#endif | |||
}; | |||
struct file_permissions | |||
: public cppcore::shifted_flags<file_permission> | |||
{ | |||
@@ -48,6 +58,12 @@ namespace cppfs | |||
public: | |||
using base_type::base_type; | |||
public: | |||
/** | |||
* @brief Get the default file permissions. | |||
*/ | |||
inline static const file_permissions& defaults(); | |||
#if cppfs_os == cppfs_os_linux | |||
public: | |||
/** | |||
@@ -0,0 +1,26 @@ | |||
#pragma once | |||
#include "misc.h" | |||
namespace cppfs | |||
{ | |||
const file_permissions& file_permissions::defaults() | |||
{ | |||
static const file_permissions value({ | |||
file_permission::user_read, | |||
file_permission::user_write, | |||
file_permission::user_execute, | |||
file_permission::group_read, | |||
file_permission::group_write, | |||
file_permission::group_execute, | |||
file_permission::others_read, | |||
file_permission::others_execute, | |||
}); | |||
return value; | |||
} | |||
} |
@@ -5,6 +5,8 @@ | |||
namespace cppfs | |||
{ | |||
/* file_permissions */ | |||
mode_t file_permissions::to_unix(const file_permissions& p_perm) | |||
{ | |||
mode_t perm = 0; | |||
@@ -43,4 +45,9 @@ namespace cppfs | |||
return perm; | |||
} | |||
/* raw_handle */ | |||
int raw_handle::handle() const | |||
{ return _handle; } | |||
} |
@@ -31,6 +31,8 @@ TEST(directory_tests, iterator) | |||
files, | |||
std::vector<std::string>({ | |||
"directory_tests.cpp", | |||
"file_events_tests.cpp", | |||
"file_tests.cpp", | |||
"path_tests.cpp", | |||
})); | |||
} |
@@ -0,0 +1,108 @@ | |||
#include <gtest/gtest.h> | |||
#include <fstream> | |||
#include <cppfs.h> | |||
using namespace ::testing; | |||
using namespace ::cppfs; | |||
struct pipe_handle | |||
: public raw_handle | |||
{ | |||
pipe_handle(int p_handle) | |||
{ | |||
_handle = p_handle; | |||
} | |||
~pipe_handle() | |||
{ | |||
close(_handle); | |||
} | |||
}; | |||
TEST(file_events_tests, select_with_callback) | |||
{ | |||
int fds[2]; | |||
ASSERT_EQ(0, pipe(fds)); | |||
pipe_handle read_handle(fds[0]); | |||
pipe_handle write_handle(fds[1]); | |||
file_events<fe_select> fe; | |||
fe.add(read_handle, event_types::all()); | |||
fe.add(write_handle, event_types::all()); | |||
auto timeout = event_clock::now(); | |||
fe.wait( | |||
[&](auto fd, auto events) { | |||
EXPECT_EQ(fd, write_handle.handle()); | |||
}, | |||
&timeout); | |||
write(write_handle.handle(), "fuuu", 4); | |||
auto i = 0; | |||
fe.wait( | |||
[&](auto fd, auto events) { | |||
switch (i) | |||
{ | |||
case 0: | |||
EXPECT_EQ(fd, read_handle.handle()); | |||
EXPECT_EQ(events, event_types(event_type::read)); | |||
break; | |||
case 1: | |||
EXPECT_EQ(fd, write_handle.handle()); | |||
EXPECT_EQ(events, event_types(event_type::write)); | |||
break; | |||
} | |||
++i; | |||
}, | |||
&timeout); | |||
} | |||
TEST(file_events_tests, select_with_result) | |||
{ | |||
int fds[2]; | |||
ASSERT_EQ(0, pipe(fds)); | |||
pipe_handle read_handle(fds[0]); | |||
pipe_handle write_handle(fds[1]); | |||
file_events<fe_select> fe; | |||
fe.add(read_handle, event_types::all()); | |||
fe.add(write_handle, event_types::all()); | |||
auto timeout = event_clock::now(); | |||
auto ret = fe.wait(&timeout); | |||
EXPECT_TRUE (ret.is_set()); | |||
EXPECT_FALSE(ret.is_set(event_type::read)); | |||
EXPECT_TRUE (ret.is_set(event_type::write)); | |||
EXPECT_FALSE(ret.is_set(event_type::except)); | |||
EXPECT_FALSE(ret.is_set(event_type::read, read_handle)); | |||
EXPECT_FALSE(ret.is_set(event_type::write, read_handle)); | |||
EXPECT_FALSE(ret.is_set(event_type::except, read_handle)); | |||
EXPECT_FALSE(ret.is_set(event_type::read, write_handle)); | |||
EXPECT_TRUE (ret.is_set(event_type::write, write_handle)); | |||
EXPECT_FALSE(ret.is_set(event_type::except, write_handle)); | |||
write(write_handle.handle(), "fuuu", 4); | |||
ret = fe.wait(&timeout); | |||
EXPECT_TRUE (ret.is_set()); | |||
EXPECT_TRUE (ret.is_set(event_type::read)); | |||
EXPECT_TRUE (ret.is_set(event_type::write)); | |||
EXPECT_FALSE(ret.is_set(event_type::except)); | |||
EXPECT_TRUE (ret.is_set(event_type::read, read_handle)); | |||
EXPECT_FALSE(ret.is_set(event_type::write, read_handle)); | |||
EXPECT_FALSE(ret.is_set(event_type::except, read_handle)); | |||
EXPECT_FALSE(ret.is_set(event_type::read, write_handle)); | |||
EXPECT_TRUE (ret.is_set(event_type::write, write_handle)); | |||
EXPECT_FALSE(ret.is_set(event_type::except, write_handle)); | |||
} |
@@ -0,0 +1,73 @@ | |||
#include <gtest/gtest.h> | |||
#include <fstream> | |||
#include <cppfs.h> | |||
using namespace ::testing; | |||
using namespace ::cppfs; | |||
TEST(file_tests, exists) | |||
{ | |||
EXPECT_FALSE(file("./cppfs").exists()); | |||
EXPECT_TRUE (file("./cppfs/file_tests.cpp").exists()); | |||
EXPECT_FALSE(file("./cppfs/asdf.txt").exists()); | |||
} | |||
TEST(file_tests, size) | |||
{ | |||
EXPECT_EQ(1619, file("./cppfs/file_tests.cpp").size()); | |||
} | |||
TEST(file_tests, open_close_and_remove) | |||
{ | |||
EXPECT_ANY_THROW(file("/tmp/cppfs/file_tests/test.file").open(access_mode::read_write)); | |||
file f("/tmp/cppfs_file_tests.test_file"); | |||
f.open(access_mode::read_write, open_flag::create); | |||
f.close(); | |||
EXPECT_TRUE(f.exists()); | |||
f.remove(); | |||
EXPECT_FALSE(f.exists()); | |||
} | |||
TEST(file_tests, open_write_close_remove) | |||
{ | |||
file f("/tmp/cppfs_file_tests.write_file"); | |||
f.open(access_mode::write_only, open_flag::create); | |||
EXPECT_EQ(15, f.write("Hello World :)\n", 15)); | |||
f.close(); | |||
std::string s; | |||
std::getline(std::ifstream("/tmp/cppfs_file_tests.write_file"), s); | |||
EXPECT_EQ(s, "Hello World :)"); | |||
EXPECT_TRUE(f.exists()); | |||
f.remove(); | |||
EXPECT_FALSE(f.exists()); | |||
} | |||
TEST(file_tests, open_read_close_remove) | |||
{ | |||
std::ofstream("/tmp/cppfs_file_tests.read_file") << "Hello World :)" << std::endl; | |||
char buffer[100] = { }; | |||
file f("/tmp/cppfs_file_tests.read_file"); | |||
f.open(access_mode::read_only); | |||
EXPECT_EQ(15, f.read(&buffer[0], sizeof(buffer))); | |||
f.close(); | |||
EXPECT_EQ(std::string(&buffer[0]), std::string("Hello World :)\n")); | |||
EXPECT_TRUE(f.exists()); | |||
f.remove(); | |||
EXPECT_FALSE(f.exists()); | |||
} |