diff --git a/groups/bdl/bdls/bdls_tempdirectoryguard.cpp b/groups/bdl/bdls/bdls_tempdirectoryguard.cpp index 896edd1c8f..786f264c99 100644 --- a/groups/bdl/bdls/bdls_tempdirectoryguard.cpp +++ b/groups/bdl/bdls/bdls_tempdirectoryguard.cpp @@ -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) { @@ -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 { diff --git a/groups/bdl/bdls/bdls_tempdirectoryguard.h b/groups/bdl/bdls/bdls_tempdirectoryguard.h index 0bbd919d00..0c969ce3f4 100644 --- a/groups/bdl/bdls/bdls_tempdirectoryguard.h +++ b/groups/bdl/bdls/bdls_tempdirectoryguard.h @@ -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&); @@ -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 diff --git a/groups/bdl/bdls/bdls_tempdirectoryguard.t.cpp b/groups/bdl/bdls/bdls_tempdirectoryguard.t.cpp index 1649f20e7f..92986c5b2b 100644 --- a/groups/bdl/bdls/bdls_tempdirectoryguard.t.cpp +++ b/groups/bdl/bdls/bdls_tempdirectoryguard.t.cpp @@ -9,6 +9,11 @@ #include +#include +#include +#include +#include + #include #include @@ -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 //----------------------------------------------------------------------------- @@ -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. @@ -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 @@ -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();