From 023b41dda06f0410da1cbac7641cc127116d5404 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Sat, 19 Jun 2021 19:56:05 +0200 Subject: [PATCH] Add helpers CMake target for convenience functions --- CMake/FindFilesystem.cmake | 247 +++++++++++++++++++++ CMakeLists.txt | 5 + tests/unit/CMakeLists.txt | 10 +- tests/unit/helpers/CMakeLists.txt | 45 ++++ tests/unit/helpers/helpers.hpp | 159 +++++++++++++ tests/unit/helpers/random_string.cpp | 54 +++++ tests/unit/helpers/temporary_directory.cpp | 59 +++++ tests/unit/helpers/temporary_file.cpp | 72 ++++++ tests/unit/test_helpers.cpp | 176 +++++++++++++++ 9 files changed, 824 insertions(+), 3 deletions(-) create mode 100644 CMake/FindFilesystem.cmake create mode 100644 tests/unit/helpers/CMakeLists.txt create mode 100644 tests/unit/helpers/helpers.hpp create mode 100644 tests/unit/helpers/random_string.cpp create mode 100644 tests/unit/helpers/temporary_directory.cpp create mode 100644 tests/unit/helpers/temporary_file.cpp create mode 100644 tests/unit/test_helpers.cpp diff --git a/CMake/FindFilesystem.cmake b/CMake/FindFilesystem.cmake new file mode 100644 index 000000000..74080895f --- /dev/null +++ b/CMake/FindFilesystem.cmake @@ -0,0 +1,247 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: + +FindFilesystem +############## + +This module supports the C++17 standard library's filesystem utilities. Use the +:imp-target:`std::filesystem` imported target to + +Options +******* + +The ``COMPONENTS`` argument to this module supports the following values: + +.. find-component:: Experimental + :name: fs.Experimental + + Allows the module to find the "experimental" Filesystem TS version of the + Filesystem library. This is the library that should be used with the + ``std::experimental::filesystem`` namespace. + +.. find-component:: Final + :name: fs.Final + + Finds the final C++17 standard version of the filesystem library. + +If no components are provided, behaves as if the +:find-component:`fs.Final` component was specified. + +If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are +provided, first looks for ``Final``, and falls back to ``Experimental`` in case +of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all +:ref:`variables ` will refer to the ``Final`` version. + + +Imported Targets +**************** + +.. imp-target:: std::filesystem + + The ``std::filesystem`` imported target is defined when any requested + version of the C++ filesystem library has been found, whether it is + *Experimental* or *Final*. + + If no version of the filesystem library is available, this target will not + be defined. + + .. note:: + This target has ``cxx_std_17`` as an ``INTERFACE`` + :ref:`compile language standard feature `. Linking + to this target will automatically enable C++17 if no later standard + version is already required on the linking target. + + +.. _fs.variables: + +Variables +********* + +.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL + + Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++ + filesystem library was found, otherwise ``FALSE``. + +.. variable:: CXX_FILESYSTEM_HAVE_FS + + Set to ``TRUE`` when a filesystem header was found. + +.. variable:: CXX_FILESYSTEM_HEADER + + Set to either ``filesystem`` or ``experimental/filesystem`` depending on + whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was + found. + +.. variable:: CXX_FILESYSTEM_NAMESPACE + + Set to either ``std::filesystem`` or ``std::experimental::filesystem`` + depending on whether :find-component:`fs.Final` or + :find-component:`fs.Experimental` was found. + + +Examples +******** + +Using `find_package(Filesystem)` with no component arguments: + +.. code-block:: cmake + + find_package(Filesystem REQUIRED) + + add_executable(my-program main.cpp) + target_link_libraries(my-program PRIVATE std::filesystem) + + +#]=======================================================================] + + +if(TARGET std::filesystem) + # This module has already been processed. Don't do it again. + return() +endif() + +cmake_minimum_required(VERSION 3.10) + +include(CMakePushCheckState) +include(CheckIncludeFileCXX) + +# If we're not cross-compiling, try to run test executables. +# Otherwise, assume that compile + link is a sufficient check. +if(CMAKE_CROSSCOMPILING) + include(CheckCXXSourceCompiles) + macro(_cmcm_check_cxx_source code var) + check_cxx_source_compiles("${code}" ${var}) + endmacro() +else() + include(CheckCXXSourceRuns) + macro(_cmcm_check_cxx_source code var) + check_cxx_source_runs("${code}" ${var}) + endmacro() +endif() + +cmake_push_check_state() + +set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY}) + +# All of our tests required C++17 or later +set(CMAKE_CXX_STANDARD 17) + +# Normalize and check the component list we were given +set(want_components ${Filesystem_FIND_COMPONENTS}) +if(Filesystem_FIND_COMPONENTS STREQUAL "") + set(want_components Final) +endif() + +# Warn on any unrecognized components +set(extra_components ${want_components}) +list(REMOVE_ITEM extra_components Final Experimental) +foreach(component IN LISTS extra_components) + message(WARNING "Extraneous find_package component for Filesystem: ${component}") +endforeach() + +# Detect which of Experimental and Final we should look for +set(find_experimental TRUE) +set(find_final TRUE) +if(NOT "Final" IN_LIST want_components) + set(find_final FALSE) +endif() +if(NOT "Experimental" IN_LIST want_components) + set(find_experimental FALSE) +endif() + +if(find_final) + check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER) + mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER) + if(_CXX_FILESYSTEM_HAVE_HEADER) + # We found the non-experimental header. Don't bother looking for the + # experimental one. + set(find_experimental FALSE) + endif() +else() + set(_CXX_FILESYSTEM_HAVE_HEADER FALSE) +endif() + +if(find_experimental) + check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER) + mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER) +else() + set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE) +endif() + +if(_CXX_FILESYSTEM_HAVE_HEADER) + set(_have_fs TRUE) + set(_fs_header filesystem) + set(_fs_namespace std::filesystem) + set(_is_experimental FALSE) +elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER) + set(_have_fs TRUE) + set(_fs_header experimental/filesystem) + set(_fs_namespace std::experimental::filesystem) + set(_is_experimental TRUE) +else() + set(_have_fs FALSE) +endif() + +set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers") +set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs") +set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs") +set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version") + +set(_found FALSE) + +if(CXX_FILESYSTEM_HAVE_FS) + # We have some filesystem library available. Do link checks + string(CONFIGURE [[ + #include + #include <@CXX_FILESYSTEM_HEADER@> + + int main() { + auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path(); + printf("%s", cwd.c_str()); + return EXIT_SUCCESS; + } + ]] code @ONLY) + + # Check a simple filesystem program without any linker flags + _cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED) + + set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED}) + + if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED) + set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES}) + # Add the libstdc++ flag + set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs) + _cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED) + set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED}) + if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED) + # Try the libc++ flag + set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs) + _cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED) + set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED}) + endif() + endif() + + if(can_link) + add_library(std::filesystem INTERFACE IMPORTED) + set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17) + set(_found TRUE) + + if(CXX_FILESYSTEM_NO_LINK_NEEDED) + # Nothing to add... + elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED) + set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs) + elseif(CXX_FILESYSTEM_CPPFS_NEEDED) + set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs) + endif() + endif() +endif() + +cmake_pop_check_state() + +set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE) + +if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND) + message(FATAL_ERROR "Cannot run simple program using std::filesystem") +endif() \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 805e2fb8f..3061cc5b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,11 @@ find_package(Boost 1.53 REQUIRED find_package(Threads REQUIRED) +# some compilers need extra flags for std::filesystem, such as -lstdc++fs, this +# produces a std::filesystem imported target that takes care of all these +# details transparently +find_package(Filesystem REQUIRED) + find_package(Date REQUIRED) option(CREATE_CHECK_PARENTS "Check parent directory existance before creating child node" ON) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 4c3697a75..dbdbcddb5 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -47,7 +47,9 @@ if(NOT catch2_POPULATED) add_subdirectory(${catch2_SOURCE_DIR} ${catch2_BINARY_DIR}) endif() -# create a convenience library with Catch2's main +add_subdirectory(helpers) + +# create a convenience library with Catch2's main # to speed up test compilation add_library(catch2_main STATIC catch_main.cpp @@ -62,14 +64,16 @@ target_link_libraries(catch2_main add_executable(tests test_example_00.cpp test_example_01.cpp - test_utils_arithmetic.cpp + test_utils_arithmetic.cpp + test_helpers.cpp test_guided_distributor.cpp ) target_link_libraries(tests catch2_main fmt::fmt - arithmetic + helpers + arithmetic distributor ) diff --git a/tests/unit/helpers/CMakeLists.txt b/tests/unit/helpers/CMakeLists.txt new file mode 100644 index 000000000..aef19067c --- /dev/null +++ b/tests/unit/helpers/CMakeLists.txt @@ -0,0 +1,45 @@ +################################################################################ +# Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain # +# Copyright 2015-2021, Johannes Gutenberg Universitaet Mainz, Germany # +# # +# This software was partially supported by the # +# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # +# # +# This software was partially supported by the # +# ADA-FS project under the SPPEXA project funded by the DFG. # +# # +# This file is part of GekkoFS. # +# # +# GekkoFS is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# GekkoFS is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with GekkoFS. If not, see . # +# # +# SPDX-License-Identifier: GPL-3.0-or-later # +################################################################################ + +add_library(helpers STATIC) + +target_sources(helpers + PRIVATE + helpers.hpp + random_string.cpp + temporary_directory.cpp + temporary_file.cpp + ) + +target_code_coverage(helpers AUTO) + +target_link_libraries(helpers + PUBLIC + fmt::fmt + std::filesystem + ) diff --git a/tests/unit/helpers/helpers.hpp b/tests/unit/helpers/helpers.hpp new file mode 100644 index 000000000..dba166cf6 --- /dev/null +++ b/tests/unit/helpers/helpers.hpp @@ -0,0 +1,159 @@ +/* + Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2021, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#ifndef GKFS_TESTS_HELPERS +#define GKFS_TESTS_HELPERS + +#include +#include +#include + +namespace fs = std::filesystem; + +namespace helpers { + +/** + * Generate a random string of length `length`. + * + * @param length The length of the random string. + * @return The generated string. + */ +std::string +random_string(std::size_t length); + + +/** + * Read the contents of `filename` returning them into `str`. + * + * @param filename The filename to read data from. + * @param str The string where data will be copied. + */ +inline void +load_string_file(const fs::path& filename, std::string& str) { + + std::ifstream file; + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + file.open(filename, std::ios_base::binary); + + auto sz = static_cast(fs::file_size(filename)); + str.resize(sz, '\0'); + file.read(&str[0], static_cast(sz)); +} + +/** + * A temporary directory with RAII removal + */ +struct temporary_directory { + + /** + * Create a temporary directory with a random dirname. + * The directory is created at a location suitable for temporary files. + */ + temporary_directory(); + + /** + * Remove a temporary directory and all its contents. + */ + ~temporary_directory(); + + /** + * Return the path of the created temporary directory. + * + * @return The path of the created directory. + */ + [[nodiscard]] fs::path + dirname() const; + + fs::path dirname_; +}; + +/** + * A temporary file with RAII removal + */ +struct temporary_file { + + /** + * Create an empty temporary file with `filename` as its name. + * + * @param filename The desired filename for the file. + */ + explicit temporary_file(fs::path filename); + + /** + * Create a temporary file with `filename` as its name and `text` as its + * contents. + * + * @param filename The desired filename for the file. + * @param text The text to be used for contents. + */ + temporary_file(fs::path filename, const std::string_view& text); + + /** + * Destroy and remove a temporary file. + */ + ~temporary_file(); + + /** + * Write text data to the temporary file. + * + * @param text The text to write. + */ + void + write(const std::string_view& text); + + /** + * Write binary data to the temporary file. + * + * @param text The binary data to write. + */ + void + write(const std::vector& data); + + /** + * Return the `filename` for the temporary file. + * + * @return The temporary file's `filename`. + */ + fs::path + filename() const; + + /** + * Return the `size` for the temporary file. + * + * @return The temporary file's `size`. + */ + std::size_t + size() const; + + fs::path filename_; + std::ofstream ofs_; +}; + +} // namespace helpers + +#endif // GKFS_TESTS_HELPERS \ No newline at end of file diff --git a/tests/unit/helpers/random_string.cpp b/tests/unit/helpers/random_string.cpp new file mode 100644 index 000000000..d4c8ca5cd --- /dev/null +++ b/tests/unit/helpers/random_string.cpp @@ -0,0 +1,54 @@ +/* + Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2021, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#include +#include +#include +#include + +namespace helpers { + +std::string +random_string(std::size_t length) { + constexpr std::array charset{"0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"}; + + thread_local static std::mt19937 rng{std::random_device{}()}; + thread_local static std::uniform_int_distribution + pick(0, std::size(charset) - 1); + + std::string s(length, '\0'); + + std::generate_n(std::begin(s), length, + [&]() { return charset[pick(rng)]; }); + + return s; +} + +} // namespace helpers \ No newline at end of file diff --git a/tests/unit/helpers/temporary_directory.cpp b/tests/unit/helpers/temporary_directory.cpp new file mode 100644 index 000000000..95f39a933 --- /dev/null +++ b/tests/unit/helpers/temporary_directory.cpp @@ -0,0 +1,59 @@ +/* + Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2021, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#include +#include "helpers.hpp" + +namespace fs = std::filesystem; + +namespace helpers { + + +temporary_directory::temporary_directory() + : dirname_(fs::temp_directory_path() / random_string(16)) { + + std::error_code ec; + fs::create_directory(dirname_, ec); + + if(ec) { + throw std::runtime_error(fmt::format("Error creating temporary " + "directory: {}", + ec.message())); + } +} + +temporary_directory::~temporary_directory() { + fs::remove_all(dirname_); +} + +fs::path +temporary_directory::dirname() const { + return dirname_; +} + +} // namespace helpers \ No newline at end of file diff --git a/tests/unit/helpers/temporary_file.cpp b/tests/unit/helpers/temporary_file.cpp new file mode 100644 index 000000000..9c8836633 --- /dev/null +++ b/tests/unit/helpers/temporary_file.cpp @@ -0,0 +1,72 @@ +/* + Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2021, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#include "helpers.hpp" + +namespace fs = std::filesystem; + +namespace helpers { + +temporary_file::temporary_file(fs::path filename) + : filename_(std::move(filename)), ofs_(filename_) {} + +temporary_file::temporary_file(fs::path filename, const std::string_view& text) + : filename_(std::move(filename)), ofs_(filename_) { + write(text); +} + +temporary_file::~temporary_file() { + ofs_.close(); + fs::remove(filename_); +} + +void +temporary_file::write(const std::string_view& text) { + ofs_ << text; + ofs_.flush(); +} + +void +temporary_file::write(const std::vector& data) { + for(const auto n : data) { + ofs_ << n; + } + ofs_.flush(); +} + +fs::path +temporary_file::filename() const { + return filename_; +} + +std::size_t +temporary_file::size() const { + return fs::file_size(filename_); +} + +} // namespace helpers \ No newline at end of file diff --git a/tests/unit/test_helpers.cpp b/tests/unit/test_helpers.cpp new file mode 100644 index 000000000..27d90e6b4 --- /dev/null +++ b/tests/unit/test_helpers.cpp @@ -0,0 +1,176 @@ +/* + Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2021, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#include +#include "helpers/helpers.hpp" + +SCENARIO("random strings can be generated", "[test_helpers][random_string]") { + + GIVEN("A desired length ") { + + WHEN("Length is zero ") { + + const auto s = helpers::random_string(0); + + THEN(" The generated string is empty ") { + REQUIRE(s.empty()); + REQUIRE(s.length() == 0); + } + } + + WHEN("Length is a positive integer") { + + const auto s = helpers::random_string(6); + + THEN(" The generated string is empty ") { + REQUIRE(s.length() == 6); + } + } + } +} + +SCENARIO(" temporary directories can be created ", + "[test_helpers][temporary_directory]") { + + GIVEN(" a temporary directory ") { + + auto tmpdir = std::make_unique(); + + WHEN(" dirname is called ") { + THEN(" a corresponding directory has been created ") { + REQUIRE(fs::exists(tmpdir->dirname())); + } + } + + WHEN(" the temporary_directory has been destroyed ") { + + const auto dirname = tmpdir->dirname(); + tmpdir.reset(); + + REQUIRE(!fs::exists(dirname)); + } + } +} + +SCENARIO(" temporary files can be created ", "[test_helpers][temporary_file]") { + + + GIVEN(" a filename ") { + const std::string filename{"foobar"}; + + AND_GIVEN(" a temporary file ") { + + auto tmpfile = std::make_unique(filename); + + WHEN(" a temporary_file is created ") { + + THEN(" a corresponding temporary file is created ") { + REQUIRE(tmpfile->filename() == filename); + REQUIRE(fs::exists(tmpfile->filename())); + } + } + + WHEN(" a temporary_file is destroyed ") { + + tmpfile.reset(); + + THEN(" the file is removed ") { + + REQUIRE(!fs::exists(filename)); + } + } + + WHEN(" text data is written to the file ") { + + const std::string text{"sometext"}; + tmpfile->write(text); + + THEN(" its contents match the provided text ") { + + std::string contents; + helpers::load_string_file(tmpfile->filename(), contents); + + REQUIRE(contents == text); + } + } + } + + AND_GIVEN(" some text for data ") { + + const std::string text{"sometext"}; + + AND_GIVEN(" a temporary file ") { + + auto tmpfile = std::make_unique( + filename, text); + + WHEN(" a temporary_file is created ") { + + THEN(" a corresponding temporary file is created ") { + REQUIRE(tmpfile->filename() == filename); + REQUIRE(fs::exists(tmpfile->filename())); + + AND_THEN(" its contents match the provided text ") { + + std::string contents; + helpers::load_string_file(tmpfile->filename(), + contents); + + REQUIRE(contents == text); + } + } + } + + WHEN(" a temporary_file is destroyed ") { + + tmpfile.reset(); + + THEN(" the file is removed ") { + tmpfile.reset(); + + REQUIRE(!fs::exists(filename)); + } + } + + WHEN(" text data is written to the file ") { + + const std::string more_text{"moretext"}; + tmpfile->write(more_text); + + THEN(" its contents match the provided text ") { + + std::string contents; + helpers::load_string_file(tmpfile->filename(), contents); + + REQUIRE(contents == text + more_text); + } + } + } + } + } +} \ No newline at end of file -- GitLab