Skip to content

Commit

Permalink
Add a release method to bdls_tempdirectoryguard (#5081)
Browse files Browse the repository at this point in the history
* Add a release method to bdls_tempdirectoryguard

* apply review feedback
  • Loading branch information
mversche authored and GitHub Enterprise committed Nov 18, 2024
1 parent 7960a30 commit c4df872
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 13 deletions.
19 changes: 14 additions & 5 deletions groups/bdl/bdls/bdls_tempdirectoryguard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ BSLS_IDENT_RCSID(bdls_tempdirectoryguard_cpp, "$Id$ $CSID$")
namespace BloombergLP {
namespace bdls {

TempDirectoryGuard::TempDirectoryGuard(const bsl::string& prefix,
bslma::Allocator *basicAllocator)
TempDirectoryGuard::TempDirectoryGuard(const bsl::string_view& prefix,
bslma::Allocator *basicAllocator)
: d_dirName(bslma::Default::allocator(basicAllocator))
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
bsl::string tmpPath(d_allocator_p);
bsl::string tmpPath;

int rc = FilesystemUtil::getSystemTemporaryDirectory(&tmpPath);
if (0 != rc) {
Expand All @@ -34,13 +33,23 @@ TempDirectoryGuard::TempDirectoryGuard(const bsl::string& prefix,
if (0 != rc) {
BSLS_ASSERT_INVOKE("Unable to create temporary directory");
}
BSLS_ASSERT_OPT(!d_dirName.empty());
}

TempDirectoryGuard::~TempDirectoryGuard()
{
bdls::FilesystemUtil::remove(d_dirName, true);
if (!d_dirName.empty()) {
bdls::FilesystemUtil::remove(d_dirName, true);
}
}

// ACCESSORS
void TempDirectoryGuard::release()
{
d_dirName.clear();
}


// ACCESSORS
const bsl::string& TempDirectoryGuard::getTempDirName() const
{
Expand Down
16 changes: 11 additions & 5 deletions groups/bdl/bdls/bdls_tempdirectoryguard.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ namespace bdls {
class TempDirectoryGuard {

// DATA
bsl::string d_dirName; // path to the created directory
bslma::Allocator *d_allocator_p; // memory allocator (held, not owned)
bsl::string d_dirName; // path to the created directory

// NOT IMPLEMENTED
TempDirectoryGuard(const TempDirectoryGuard&);
Expand All @@ -89,18 +88,25 @@ class TempDirectoryGuard {
/// system-wide temp or current directory. Optionally specify a
/// `basicAllocator` used to supply memory. If `basicAllocator` is 0, the
/// currently installed default allocator is used.
explicit TempDirectoryGuard(const bsl::string& prefix,
bslma::Allocator *basicAllocator = 0);
explicit TempDirectoryGuard(const bsl::string_view& prefix,
bslma::Allocator *basicAllocator = 0);

/// Destroy this object and remove the temporary directory (recursively)
/// created at construction.
~TempDirectoryGuard();

/// Remove the created temporary directory from management so that, upon this guards
/// destruction, the created directory is not removed. Calling `release` on a guard
/// that has previously been released has no effect.
void release();

// ACCESSORS

/// Return a `const` reference to the name of the created temporary
/// directory.
/// directory, or an empty string if the directory was released
/// from management.
const bsl::string& getTempDirName() const;

};

} // close package namespace
Expand Down
238 changes: 235 additions & 3 deletions groups/bdl/bdls/bdls_tempdirectoryguard.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@

#include <bslim_testutil.h>

#include <bslma_default.h>
#include <bslma_defaultallocatorguard.h>
#include <bslma_testallocator.h>
#include <bslma_usesbslmaallocator.h>

#include <bsl_iostream.h>

#include <bsl_cstdlib.h>
Expand All @@ -19,8 +24,22 @@ using namespace bsl; // automatically added by script
//=============================================================================
// TEST PLAN
//-----------------------------------------------------------------------------
// Overview
// --------
// `bdls::TempDirectoryGuard` provides a guard type with a minimal interface.
// A constructor, destructor, and a release method.
// ----------------------------------------------------------------------------
// CONSTRUCTORS
// [ 2] TempDirectoryGuard(const bsl::string_view&, Allocator *);
// [ 2] ~TempDirectoryGuard();
//
// [ 2] USAGE EXAMPLE
// MAINPULATORS
// [ 3] void release();
//
// ACCESSORS
// [ 2] const bsl::string& getTempDirName() const;
// ----------------------------------------------------------------------------
// [ 4] USAGE EXAMPLE
// [ 1] BREATHING TEST
//-----------------------------------------------------------------------------

Expand Down Expand Up @@ -131,7 +150,7 @@ int main(int argc, char *argv[])
cout << "TEST " << __FILE__ << " CASE " << test << endl;

switch (test) { case 0: // Zero is always the leading case.
case 2: {
case 4: {
// --------------------------------------------------------------------
// USAGE EXAMPLE
// Extracted from component header file.
Expand All @@ -156,6 +175,220 @@ int main(int argc, char *argv[])
usesTestAlgorithm();

} break;
case 3: {
// --------------------------------------------------------------------
// TESTING: release
//
// Concerns:
// 1. That the `release` method, after being called will release the
// created temporary directory.
//
// 2. Calling `release` subsequently has no effect.
//
// Plan:
// 1. Create a guard, and call release on it multiple times. Destroy
// the guard and verify that the directory still exists. (C1, C2)
//
// Testing:
// void release();
// --------------------------------------------------------------------

if (verbose) cout << endl
<< "TESTING: release" << endl
<< "================" << endl;

{
bsl::string name;
const bsl::string_view prefix = "testCase3_";

{
bdls::TempDirectoryGuard guard(prefix);

name = guard.getTempDirName();

ASSERTV(name, bdls::FilesystemUtil::exists(name));
ASSERTV(name, bdls::FilesystemUtil::isDirectory(name));

guard.release();

ASSERTV(guard.getTempDirName(),
true == guard.getTempDirName().empty());

guard.release();

ASSERTV(guard.getTempDirName(),
true == guard.getTempDirName().empty());

}

ASSERTV(name, bdls::FilesystemUtil::exists(name));
ASSERTV(name, bdls::FilesystemUtil::isDirectory(name));

bdls::FilesystemUtil::remove(name);

ASSERTV(name, !bdls::FilesystemUtil::exists(name));
ASSERTV(name, !bdls::FilesystemUtil::isDirectory(name));
}


} break;
case 2: {
// --------------------------------------------------------------------
// TESTING: DEFAULT CTOR, DTOR, PRIMARY ACCESSOR
//
// Concerns:
// 1. The constructor creates a temporary directory using the
// supplied prefix for its name.
//
// 2. The constructor supports an empty prefix.
//
// 3. The guard creates a directory with a unique name even when the
// prefix is the same.
//
// 4. The constructor uses the supplied allocator to allocate
// memory.
//
// 5. `getTempDirName` returns the name of the created directory.
//
// 6. The destructor removes the created directory and frees any
// allocated memory.
//
// Plan:
// 1. Create a guard with a supplied object allocator and a long
// string prefix (C1, C4, C5, C6)
//
// 2. Create a guard with the default allocator (C-4)
//
// 3. Create a guard with an empty prefix (C-2)
//
// 4. Create multiple guards with the same prefix (C-3)
//
// Testing:
// TempDirectoryGuard(const bsl::string_view&, Allocator *);
// ~TempDirectoryGuard();
// const bsl::string& getTempDirName() const;
// --------------------------------------------------------------------

if (verbose) cout << endl
<< "TESTING: bootstrap" << endl
<< "==================" << endl;


bsl::string name;

bslma::TestAllocator da("default", veryVeryVerbose);
bslma::TestAllocator oa("object", veryVeryVerbose);
bslma::DefaultAllocatorGuard dag(&da);

if (verbose) {
cout << "Test basic behavior with supplied allocator" << endl;
}
{
const bsl::string_view prefix = "testCase2WithALongString_";

{
bdls::TempDirectoryGuard guard(prefix, &oa);

ASSERTV(da.numBytesInUse(), 0 == da.numBytesInUse());
ASSERTV(oa.numBytesInUse(), 0 < oa.numBytesInUse());

name = guard.getTempDirName();

ASSERTV(name, bdls::FilesystemUtil::exists(name));
ASSERTV(name, bdls::FilesystemUtil::isDirectory(name));

bsl::string_view head, tail;
bdls::PathUtil::splitFilename(&head, &tail, name);

ASSERTV(head, tail, tail.starts_with(prefix));
}

ASSERTV(name, !bdls::FilesystemUtil::exists(name));
ASSERTV(name, !bdls::FilesystemUtil::isDirectory(name));
}

if (verbose) {
cout << "Test basic with default allocator" << endl;
}
{
const bsl::string_view prefix = "testCase2WithALongString_";

{
bdls::TempDirectoryGuard guard(prefix);

ASSERTV(da.numBytesInUse(), 0 < da.numBytesInUse());
ASSERTV(oa.numBytesInUse(), 0 == oa.numBytesInUse());

name = guard.getTempDirName();

ASSERTV(name, bdls::FilesystemUtil::exists(name));
ASSERTV(name, bdls::FilesystemUtil::isDirectory(name));

bsl::string_view head, tail;
bdls::PathUtil::splitFilename(&head, &tail, name);

ASSERTV(head, tail, tail.starts_with(prefix));
}

ASSERTV(name, !bdls::FilesystemUtil::exists(name));
ASSERTV(name, !bdls::FilesystemUtil::isDirectory(name));
}


if (verbose) {
cout << "Test with an empty prefix" << endl;
}
{
const bsl::string_view prefix = "";

{
bdls::TempDirectoryGuard guard(prefix);

name = guard.getTempDirName();

ASSERTV(name, bdls::FilesystemUtil::exists(name));
ASSERTV(name, bdls::FilesystemUtil::isDirectory(name));
}

ASSERTV(name, !bdls::FilesystemUtil::exists(name));
ASSERTV(name, !bdls::FilesystemUtil::isDirectory(name));
}

if (verbose) {
cout << "Test with re-using a prefix" << endl;
}
{
const bsl::string_view prefix = "testCase2ReusedPrefix";
bsl::string name1, name2, name3;
{
bdls::TempDirectoryGuard guard1(prefix);
bdls::TempDirectoryGuard guard2(prefix);
bdls::TempDirectoryGuard guard3(prefix);

name1 = guard1.getTempDirName();
name2 = guard2.getTempDirName();
name3 = guard3.getTempDirName();

ASSERTV(name1, name2, name1 != name2);
ASSERTV(name1, name3, name1 != name3);
ASSERTV(name2, name3, name2 != name3);

ASSERTV(name1, bdls::FilesystemUtil::exists(name1));
ASSERTV(name1, bdls::FilesystemUtil::isDirectory(name1));

ASSERTV(name2, bdls::FilesystemUtil::exists(name2));
ASSERTV(name2, bdls::FilesystemUtil::isDirectory(name2));

ASSERTV(name3, bdls::FilesystemUtil::exists(name3));
ASSERTV(name3, bdls::FilesystemUtil::isDirectory(name3));
}

ASSERTV(name1, !bdls::FilesystemUtil::exists(name1));
ASSERTV(name2, !bdls::FilesystemUtil::exists(name2));
ASSERTV(name3, !bdls::FilesystemUtil::exists(name3));

}
} break;
case 1: {
// --------------------------------------------------------------------
// BREATHING TEST
Expand Down Expand Up @@ -184,7 +417,6 @@ int main(int argc, char *argv[])
bsl::string g1dir;
bsl::string tmpfile;
bsl::string g2dir;

{
bdls::TempDirectoryGuard guard1(prefix);
g1dir = guard1.getTempDirName();
Expand Down

0 comments on commit c4df872

Please sign in to comment.