This is something I wanted to clean-up since a very long time indeed, but always postponed it, since it requires a lot of nasty clean-up and disentangling.... Several parts had been stashed away into `src/lib/test`, which are not really related: * the testrunner and testsuite builder * generic helper utilities * specialised test-support facilities, e.g. the EventLog This changeset introduces a new top-level test folder and a namespace `::test` Code from this folder is linked into a shared library `libtestsupport.so`, which resides in the linkage hierarchy between »Vessel« and »Vault«, yet is no longer part of the Lumiera application and only linked into the test-suite.
144 lines
3.9 KiB
C++
144 lines
3.9 KiB
C++
/*
|
||
TEMP-DIR.hpp - automatic allocation of a temporary working directory
|
||
|
||
Copyright (C)
|
||
2024, Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
**Lumiera** 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 2 of the License, or (at your
|
||
option) any later version. See the file COPYING for further details.
|
||
|
||
*/
|
||
|
||
|
||
/** @file temp-dir.hpp
|
||
** Manage a temporary directory for storage, with automated clean-up.
|
||
** @see TempDir_test
|
||
*/
|
||
|
||
|
||
#ifndef TESTSUPPORT_TEMP_DIR_H
|
||
#define TESTSUPPORT_TEMP_DIR_H
|
||
|
||
|
||
#include "lib/error.hpp"
|
||
#include "lib/nocopy.hpp"
|
||
#include "lib/random.hpp"
|
||
#include "include/limits.hpp"
|
||
#include "lib/format-string.hpp"
|
||
#include "lib/format-obj.hpp"
|
||
#include "lib/file.hpp"
|
||
#include "lib/util.hpp"
|
||
|
||
#include <fstream>
|
||
#include <string>
|
||
|
||
|
||
namespace test{
|
||
namespace error = lumiera::error;
|
||
|
||
using util::_Fmt;
|
||
using util::isnil;
|
||
using std::string;
|
||
|
||
namespace {
|
||
lib::Literal TEMPFILE_PREFIX = "Lux";
|
||
}
|
||
|
||
|
||
/**
|
||
* A RAII style temporary directory.
|
||
*/
|
||
class TempDir
|
||
: util::MoveOnly
|
||
{
|
||
fs::path loc_;
|
||
|
||
public:
|
||
TempDir()
|
||
: loc_{establishNewDirectory()}
|
||
{ }
|
||
|
||
~TempDir()
|
||
{
|
||
if (fs::exists (loc_))
|
||
destroyTempDirectory();
|
||
}
|
||
|
||
|
||
operator fs::path const& () const
|
||
{
|
||
return loc_;
|
||
}
|
||
|
||
fs::path
|
||
makeFile (string name ="")
|
||
{
|
||
if (isnil (name))
|
||
return establishNewFile (string{TEMPFILE_PREFIX});
|
||
|
||
auto newFile = loc_ / name;
|
||
if (fs::exists (newFile))
|
||
return establishNewFile (name);
|
||
|
||
std::ofstream{newFile};
|
||
if (fs::exists (newFile) and fs::is_empty(newFile))
|
||
return newFile;
|
||
//
|
||
throw error::Fatal{_Fmt{"Failed to create unique new file %s in TempDir."} % newFile};
|
||
}
|
||
|
||
|
||
private:
|
||
static fs::path
|
||
establishNewDirectory()
|
||
{
|
||
auto tmpDir = fs::temp_directory_path();
|
||
for (uint attempt=0; attempt<LUMIERA_MAX_COMPETITION; ++attempt)
|
||
{
|
||
auto randName = TEMPFILE_PREFIX + util::showHash (lib::entropyGen.u64());
|
||
auto newPath = tmpDir / randName;
|
||
// attempt to create it....
|
||
if (fs::create_directory (newPath)
|
||
and has_perm (newPath, fs::perms::owner_all)
|
||
and fs::is_empty (newPath)
|
||
) // success!
|
||
return newPath;
|
||
}
|
||
throw error::Fatal{_Fmt{"Failed to create unique new TempDir after %d attempts."}
|
||
% LUMIERA_MAX_COMPETITION
|
||
,error::LUMIERA_ERROR_SAFETY_LIMIT };
|
||
}
|
||
|
||
fs::path
|
||
establishNewFile (string prefix)
|
||
{
|
||
for (uint attempt=0; attempt<LUMIERA_MAX_COMPETITION; ++attempt)
|
||
{
|
||
auto randName = prefix + "." + util::showHash (lib::entropyGen.u64());
|
||
auto newPath = loc_ / randName;
|
||
// attempt to create it....
|
||
if (fs::exists(newPath))
|
||
continue;
|
||
std::ofstream{newPath};
|
||
if (fs::exists(newPath) and fs::is_empty (newPath))
|
||
return newPath; // success!
|
||
}
|
||
throw error::Fatal{_Fmt{"Failed to create unique new file at %s after %d attempts."}
|
||
% loc_ % LUMIERA_MAX_COMPETITION
|
||
,error::LUMIERA_ERROR_SAFETY_LIMIT };
|
||
}
|
||
|
||
void
|
||
destroyTempDirectory()
|
||
try {
|
||
fs::remove_all (loc_);
|
||
ENSURE (not fs::exists(loc_));
|
||
}
|
||
ERROR_LOG_AND_IGNORE (filesys, "TempDir clean-up")
|
||
};
|
||
|
||
|
||
}// namespace test
|
||
#endif /*TESTSUPPORT_TEMP_DIR_H*/
|