From 87c76ea235b95df37defe1becf7d5ddb699b4a67 Mon Sep 17 00:00:00 2001 From: jfcarroll Date: Mon, 27 Jun 2022 11:42:04 -0700 Subject: [PATCH] The file was overwritten when transferring a file that already existed in the downloads folder. With this change we now add " (x)", where x is an incrementing number, starting at 1, using the next non-existing number, to the file name, just before the first dot, or at the end if no dot. This has been applied to the GetDownloadPath method in the platform api. PiperOrigin-RevId: 457530287 --- internal/platform/implementation/g3/BUILD | 1 + .../platform/implementation/g3/platform.cc | 46 +- .../platform/implementation/shared/file.cc | 9 +- .../platform/implementation/shared/file.h | 7 +- .../implementation/shared/file_test.cc | 4 +- .../implementation/windows/platform.cc | 68 ++- .../implementation/windows/platform_test.cc | 396 +++++++++++++++--- 7 files changed, 410 insertions(+), 121 deletions(-) diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index a7447c86..2881c276 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -121,6 +121,7 @@ cc_library( ":comm", ":crypto", # build_cleaner: keep ":types", + "//file/base:path", "//internal/platform:test_util", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", diff --git a/internal/platform/implementation/g3/platform.cc b/internal/platform/implementation/g3/platform.cc index 5b316469..10a9e767 100644 --- a/internal/platform/implementation/g3/platform.cc +++ b/internal/platform/implementation/g3/platform.cc @@ -18,6 +18,7 @@ #include #include +#include "file/base/path.h" #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" #include "absl/time/time.h" @@ -60,50 +61,9 @@ namespace api { std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder, std::string& file_name) { - std::string fullPath("/tmp/"); + std::string fullPath("/tmp"); - // If parent_folder starts with a \\ or /, then strip it - while (!parent_folder.empty() && - (*parent_folder.begin() == '\\' || *parent_folder.begin() == '/')) { - parent_folder.erase(0, 1); - } - - // If parent_folder ends with a \\ or /, then strip it - while (!parent_folder.empty() && - (*parent_folder.rbegin() == '\\' || *parent_folder.rbegin() == '/')) { - parent_folder.erase(parent_folder.size() - 1); - } - - // If file_name starts with a \\, then strip it - while (!file_name.empty() && - (*file_name.begin() == '\\' || *file_name.begin() == '/')) { - file_name.erase(0, 1); - } - - // If file_name ends with a \\, then strip it - while (!file_name.empty() && - (*file_name.rbegin() == '\\' || *file_name.rbegin() == '/')) { - file_name.erase(file_name.size() - 1); - } - - std::stringstream path; - - if (parent_folder.empty() && file_name.empty()) { - path << fullPath.c_str(); - return path.str(); - } - if (parent_folder.empty()) { - path << fullPath.c_str() << "\\" << file_name.c_str(); - return path.str(); - } - if (file_name.empty()) { - path << fullPath.c_str() << "\\" << parent_folder.c_str(); - return path.str(); - } - - path << fullPath.c_str() << "\\" << parent_folder.c_str() << "\\" - << file_name.c_str(); - return path.str(); + return file::JoinPath("/tmp", file_name); } OSName ImplementationPlatform::GetCurrentOS() { return OSName::kLinux; } diff --git a/internal/platform/implementation/shared/file.cc b/internal/platform/implementation/shared/file.cc index 0d22d474..9d9d66a3 100644 --- a/internal/platform/implementation/shared/file.cc +++ b/internal/platform/implementation/shared/file.cc @@ -14,8 +14,10 @@ #include "internal/platform/implementation/shared/file.h" +#include #include #include +#include #include "absl/memory/memory.h" #include "absl/strings/string_view.h" @@ -42,10 +44,9 @@ std::unique_ptr IOFile::CreateOutputFile(const absl::string_view path) { } IOFile::IOFile(const absl::string_view file_path) - : file_(std::string(file_path.data(), file_path.size()), - std::ios::binary | std::ios::out | std::ios::trunc), - path_({file_path.data(), file_path.size()}), - total_size_(0) {} + : file_(), path_(file_path), total_size_(0) { + file_.open(path_, std::ios::binary | std::ios::out); +} ExceptionOr IOFile::Read(std::int64_t size) { if (!file_.is_open()) { diff --git a/internal/platform/implementation/shared/file.h b/internal/platform/implementation/shared/file.h index 2efcc6d4..fa96bbf5 100644 --- a/internal/platform/implementation/shared/file.h +++ b/internal/platform/implementation/shared/file.h @@ -17,6 +17,7 @@ #include #include +#include #include "absl/strings/string_view.h" #include "internal/platform/exception.h" @@ -35,9 +36,9 @@ class IOFile final : public api::InputFile, public api::OutputFile { static std::unique_ptr CreateOutputFile(const absl::string_view path); ExceptionOr Read(std::int64_t size) override; - std::string GetFilePath() const override { - return std::string(path_.data(), path_.size()); - } + + std::string GetFilePath() const override { return path_; } + std::int64_t GetTotalSize() const override { return total_size_; } Exception Close() override; diff --git a/internal/platform/implementation/shared/file_test.cc b/internal/platform/implementation/shared/file_test.cc index 367e9ff0..b4abf193 100644 --- a/internal/platform/implementation/shared/file_test.cc +++ b/internal/platform/implementation/shared/file_test.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include "file/util/temp_path.h" #include "gtest/gtest.h" @@ -133,7 +134,8 @@ TEST_F(FileTest, IOFile_Write) { ByteArray bytes2("bc"); EXPECT_EQ(io_file_output->Write(bytes1), Exception{Exception::kSuccess}); EXPECT_EQ(io_file_output->Write(bytes2), Exception{Exception::kSuccess}); - auto io_file_input = shared::IOFile::CreateInputFile(path_, GetSize()); + auto io_file_input = + shared::IOFile::CreateInputFile(io_file_output->GetFilePath(), GetSize()); AssertEquals(io_file_input->Read(kMaxSize), "abc"); } diff --git a/internal/platform/implementation/windows/platform.cc b/internal/platform/implementation/windows/platform.cc index 6cda5c07..d966fae2 100644 --- a/internal/platform/implementation/windows/platform.cc +++ b/internal/platform/implementation/windows/platform.cc @@ -49,8 +49,10 @@ namespace location { namespace nearby { namespace api { -std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder, - std::string& file_name) { + +namespace { +std::string GetDownloadPathInternal(std::string& parent_folder, + std::string& file_name) { PWSTR basePath; // Retrieves the full path of a known folder identified by the folder's @@ -69,9 +71,10 @@ std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder, // SHGetKnownFolderPath succeeds or not. size_t bufferSize; wcstombs_s(&bufferSize, NULL, 0, basePath, 0); - std::string fullpathUTF8(bufferSize, '\0'); + std::string fullpathUTF8(bufferSize - 1, '\0'); wcstombs_s(&bufferSize, fullpathUTF8.data(), bufferSize, basePath, _TRUNCATE); - std::string fullPath = fullpathUTF8; + + std::replace(fullpathUTF8.begin(), fullpathUTF8.end(), '\\', '/'); // If parent_folder starts with a \\ or /, then strip it while (!parent_folder.empty() && @@ -102,25 +105,74 @@ std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder, std::stringstream path(""); if (parent_folder.empty() && file_name.empty()) { - return fullPath; + return fullpathUTF8; } if (parent_folder.empty()) { - path << fullPath.c_str() << "\\" << file_name.c_str(); + path << fullpathUTF8.c_str() << "/" << file_name.c_str(); std::string retVal = path.str(); return retVal; } if (file_name.empty()) { - path << fullPath.c_str() << "\\" << parent_folder.c_str(); + path << fullpathUTF8.c_str() << "/" << parent_folder.c_str(); std::string retVal = path.str(); return retVal; } - path << fullPath.c_str() << "\\" << parent_folder.c_str() << "\\" + path << fullpathUTF8.c_str() << "/" << parent_folder.c_str() << "/" << file_name.c_str(); std::string retVal = path.str(); return retVal; } +// If the file already exists we add " (x)", where x is an incrementing number, +// starting at 1, using the next non-existing number, to the file name, just +// before the first dot, or at the end if no dot. The absolute path is returned. +std::string CreateOutputFileWithRename(absl::string_view path) { + auto last_separator = path.find_last_of('/'); + std::string folder(path.substr(0, last_separator)); + std::string file_name(path.substr(last_separator)); + + int count = 0; + + // Locate the first dot + auto first = file_name.find_first_of('.', 0); + + if (first == std::string::npos) { + first = file_name.size(); + } + + // Break the string at the dot. + auto file_name1 = file_name.substr(0, first); + auto file_name2 = file_name.substr(first); + + // Construct the target file name + std::string target(path); + + std::fstream file; + file.open(target, std::fstream::binary | std::fstream::in); + + // While we successfully open the file, keep incrementing the count. + while (!(file.rdstate() & std::ifstream::failbit)) { + file.close(); + target = absl::StrCat(folder, file_name1, " (", ++count, ")", file_name2); + file.clear(); + file.open(target, std::fstream::binary | std::fstream::in); + } + + // The above leaves the file open, so close it. + file.close(); + + return target; +} + +} // namespace + +std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder, + std::string& file_name) { + return CreateOutputFileWithRename( + GetDownloadPathInternal(parent_folder, file_name)); +} + OSName ImplementationPlatform::GetCurrentOS() { return OSName::kWindows; } std::unique_ptr ImplementationPlatform::CreateAtomicBoolean( diff --git a/internal/platform/implementation/windows/platform_test.cc b/internal/platform/implementation/windows/platform_test.cc index af04706a..9501f439 100644 --- a/internal/platform/implementation/windows/platform_test.cc +++ b/internal/platform/implementation/windows/platform_test.cc @@ -19,18 +19,33 @@ #include #include +#include #include "gtest/gtest.h" +namespace { +constexpr absl::string_view kFileName("/increment_file_test.txt"); +constexpr absl::string_view kFirstIterationFileName( + "/increment_file_test (1).txt"); +constexpr absl::string_view kSecondIterationFileName( + "/increment_file_test (2).txt"); +constexpr absl::string_view kThirdIterationFileName( + "/increment_file_test (3).txt"); +constexpr absl::string_view kNoDotsFileName("/incrementfiletesttxt"); +constexpr absl::string_view kOneIterationNoDotsFileName( + "/incrementfiletesttxt (1)"); +constexpr absl::string_view kMultipleDotsFileName("/increment.file.test.txt"); +constexpr absl::string_view kOneIterationMultipleDotsFileName( + "/increment (1).file.test.txt"); +} // namespace + // Can't run on google 3, I presume the SHGetKnownFolderPath // fails. #if 0 -class ImplementationPlatformTests : public testing::Test -{ +class ImplementationPlatformTests : public testing::Test { protected: // You can define per-test set-up logic as usual. - void SetUp() override - { + void SetUp() override { PWSTR basePath; SHGetKnownFolderPath( @@ -52,18 +67,19 @@ class ImplementationPlatformTests : public testing::Test size_t bufferSize; wcstombs_s(&bufferSize, NULL, 0, basePath, 0); - std::string fullpathUTF8(bufferSize, '\0'); - wcstombs_s(&bufferSize, fullpathUTF8.data(), bufferSize, basePath, + default_download_path_.resize(bufferSize - 1, '\0'); + wcstombs_s(&bufferSize, default_download_path_.data(), bufferSize, basePath, _TRUNCATE); - default_download_path_ = fullpathUTF8; + + std::replace(default_download_path_.begin(), default_download_path_.end(), + '\\', '/'); } std::string default_download_path_; }; TEST_F(ImplementationPlatformTests, - GetDownloadPathWithEmptyStringArgumentsShouldReturnBaseDownloadPath) -{ + GetDownloadPathWithEmptyStringArgumentsShouldReturnBaseDownloadPath) { // Arrange std::string parent_folder(""); std::string file_name(""); @@ -78,8 +94,7 @@ TEST_F(ImplementationPlatformTests, TEST_F(ImplementationPlatformTests, GetDownloadPathWithSlashParentFolderArgumentsShouldReturn\ -BaseDownloadPath) -{ +BaseDownloadPath) { // Arrange std::string parent_folder("/"); std::string file_name(""); @@ -94,8 +109,7 @@ BaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithBackslashParentFolderArgumentsShouldReturn\ -BaseDownloadPath) -{ +BaseDownloadPath) { // Arrange std::string parent_folder("\\"); std::string file_name(""); @@ -109,8 +123,7 @@ BaseDownloadPath) } TEST_F(ImplementationPlatformTests, - GetDownloadPathWithSlashFileNameArgumentsShouldReturnBaseDownloadPath) -{ + GetDownloadPathWithSlashFileNameArgumentsShouldReturnBaseDownloadPath) { // Arrange std::string parent_folder(""); std::string file_name("/"); @@ -125,8 +138,7 @@ TEST_F(ImplementationPlatformTests, TEST_F(ImplementationPlatformTests, GetDownloadPathWithBackslashFileNameArgumentsShouldReturn\ -BaseDownloadPath) -{ +BaseDownloadPath) { // Arrange std::string parent_folder(""); std::string file_name("\\"); @@ -144,14 +156,13 @@ BaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithParentFolderShouldReturnParentFolder\ -AppendedToBaseDownloadPath) -{ +AppendedToBaseDownloadPath) { // Arrange std::string parent_folder("test_parent_folder"); std::string file_name(""); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_parent_folder"; std::string expected = path.str(); @@ -166,14 +177,13 @@ AppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithParentFolderStartingWithSlashArgumentsShouldReturn\ -ParentFolderAppendedToBaseDownloadPath) -{ +ParentFolderAppendedToBaseDownloadPath) { // Arrange std::string parent_folder("/test_parent_folder"); std::string file_name(""); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_parent_folder"; std::string expected = path.str(); @@ -188,14 +198,13 @@ ParentFolderAppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithParentFolderStartingWithBackslashArguments\ -ShouldReturnParentFolderAppendedToBaseDownloadPath) -{ +ShouldReturnParentFolderAppendedToBaseDownloadPath) { // Arrange std::string parent_folder("\\test_parent_folder"); std::string file_name(""); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_parent_folder"; std::string expected = path.str(); @@ -210,14 +219,13 @@ ShouldReturnParentFolderAppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithParentFolderEndingWithSlashArgumentsShouldReturn\ -ParentFolderAppendedToBaseDownloadPath) -{ +ParentFolderAppendedToBaseDownloadPath) { // Arrange std::string parent_folder("test_parent_folder/"); std::string file_name(""); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_parent_folder"; std::string expected = path.str(); @@ -232,14 +240,13 @@ ParentFolderAppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithParentFolderEndingWithBackslashArguments\ -ShouldReturnParentFolderAppendedToBaseDownloadPath) -{ +ShouldReturnParentFolderAppendedToBaseDownloadPath) { // Arrange std::string parent_folder("test_parent_folder\\"); std::string file_name(""); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_parent_folder"; std::string expected = path.str(); @@ -254,14 +261,13 @@ ShouldReturnParentFolderAppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithFileNameBeginningWithSlashArgumentsShouldReturn\ -FileNameAppendedToBaseDownloadPath) -{ +FileNameAppendedToBaseDownloadPath) { // Arrange std::string parent_folder(""); std::string file_name("/test_file_name.name"); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_file_name.name"; std::string expected = path.str(); @@ -276,36 +282,32 @@ FileNameAppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithFileNameBeginningWithBackslashArgumentsShouldReturn\ -FileNameAppendedToBaseDownloadPath) -{ +FileNameAppendedToBaseDownloadPath) { // Arrange std::string parent_folder(""); std::string file_name("\\test_file_name.name"); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_file_name.name"; - std::string expected = path.str(); - // Act auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath( parent_folder, file_name); // Assert - EXPECT_EQ(result, expected); + EXPECT_EQ(result, path.str().c_str()); } TEST_F(ImplementationPlatformTests, GetDownloadPathWithFileNameEndingWithSlashArgumentsShouldReturnFileName\ -AppendedToBaseDownloadPath) -{ +AppendedToBaseDownloadPath) { // Arrange std::string parent_folder(""); std::string file_name("test_file_name.name/"); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_file_name.name"; std::string expected = path.str(); @@ -320,14 +322,13 @@ AppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithFileNameEndingWithBackslashArgumentsShouldReturn\ -FileNameAppendedToBaseDownloadPath) -{ +FileNameAppendedToBaseDownloadPath) { // Arrange std::string parent_folder(""); std::string file_name("test_file_name.name\\"); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_file_name.name"; std::string expected = path.str(); @@ -342,16 +343,15 @@ FileNameAppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithParentFolderAndFileNameArgumentsShouldReturn\ -ParentFolderAndFileNameAppendedToBaseDownloadPath) -{ +ParentFolderAndFileNameAppendedToBaseDownloadPath) { // Arrange std::string parent_folder("test_parent_folder"); std::string file_name("test_file_name.name"); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_parent_folder" - << "\\" + << "/" << "test_file_name.name"; std::string expected = path.str(); @@ -366,16 +366,15 @@ ParentFolderAndFileNameAppendedToBaseDownloadPath) TEST_F(ImplementationPlatformTests, GetDownloadPathWithParentFolderEndingWithBackslashAndFileNameArguments\ -ShouldReturnParentFolderAndFileNameAppendedToBaseDownloadPath) -{ +ShouldReturnParentFolderAndFileNameAppendedToBaseDownloadPath) { // Arrange std::string parent_folder("test_parent_folder\\"); std::string file_name("test_file_name.name"); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_parent_folder" - << "\\" + << "/" << "test_file_name.name"; std::string expected = path.str(); @@ -388,19 +387,17 @@ ShouldReturnParentFolderAndFileNameAppendedToBaseDownloadPath) EXPECT_EQ(result, expected); } -TEST_F( - ImplementationPlatformTests, - GetDownloadPathWithFileNameStartingWithBackslashAndParentFolderArguments\ -ShouldReturnParentFolderAndFileNameAppendedToBaseDownloadPath) -{ +TEST_F(ImplementationPlatformTests, + GetDownloadPathWithFileNameStartingWithBackslashAndParentFolderArguments\ +ShouldReturnParentFolderAndFileNameAppendedToBaseDownloadPath) { // Arrange std::string parent_folder("test_parent_folder"); std::string file_name("\\test_file_name.name"); std::stringstream path(""); - path << default_download_path_.c_str() << "\\" + path << default_download_path_ << "/" << "test_parent_folder" - << "\\" + << "/" << "test_file_name.name"; std::string expected = path.str(); @@ -412,4 +409,279 @@ ShouldReturnParentFolderAndFileNameAppendedToBaseDownloadPath) // Assert EXPECT_EQ(result, expected); } + +TEST_F(ImplementationPlatformTests, + GetDownloadPath_FileDoesntExistReturnsFileWithPassedName) { + // Arrange + std::string file_name(kFileName); + std::string parent_folder(""); + + std::string expected(default_download_path_); + expected.append(file_name.c_str()); + + // Act + std::string actual = + location::nearby::api::ImplementationPlatform::GetDownloadPath( + parent_folder, file_name); + + // Assert + EXPECT_EQ(actual, expected); +} + +TEST_F(ImplementationPlatformTests, + GetDownloadPath_FileExistsReturnsFileWithIncrementedName) { + // Arrange + std::string file_name(kFileName); + std::string renamed_file_name(kFirstIterationFileName); + std::string parent_folder(""); + + std::string output_file_path(default_download_path_); + output_file_path.append(file_name); + + std::string expected(default_download_path_); + expected.append(renamed_file_name.c_str()); + + std::ifstream input_file; + std::ofstream output_file; + + output_file.open(output_file_path, + std::ofstream::binary | std::ofstream::out); + + ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit); + + output_file.close(); + + // Act + std::string actual = + location::nearby::api::ImplementationPlatform::GetDownloadPath( + parent_folder, file_name); + + // Assert + EXPECT_EQ(actual, expected); + + // Remove the file and check that it is removed + // File 1 + std::remove(output_file_path.c_str()); + + input_file.open(output_file_path, std::ifstream::binary | std::ifstream::in); + + ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); +} + +TEST_F(ImplementationPlatformTests, + GetDownloadPath_MultipleFilesExistReturnsNextIncrementedFileName) { + // Arrange + std::ofstream output_file; + std::ifstream input_file; + + std::string file_name(kFileName); + std::string first_renamed_file_name(kFirstIterationFileName); + std::string second_renamed_file_name(kSecondIterationFileName); + + std::string parent_folder(""); + + std::string expected(default_download_path_); + expected.append(second_renamed_file_name.c_str()); + + std::string output_file1_path(default_download_path_); + output_file1_path.append(file_name); + + std::string output_file2_path(default_download_path_); + output_file2_path.append(first_renamed_file_name); + + // Create the test files + output_file.open(output_file1_path, + std::ofstream::binary | std::ofstream::out); + ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit); + output_file.close(); + output_file.clear(); + + output_file.open(output_file2_path, + std::ofstream::binary | std::ofstream::out); + ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit); + output_file.close(); + + // Act + std::string actual = + location::nearby::api::ImplementationPlatform::GetDownloadPath( + parent_folder, file_name); + + // Assert + EXPECT_EQ(expected, actual); + + // Remove the test files and check that it is removed + // File 1 + std::remove(output_file1_path.c_str()); + input_file.open(output_file1_path, std::ifstream::binary | std::ifstream::in); + + ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); + + // File 2 + std::remove(output_file2_path.c_str()); + + input_file.clear(); + input_file.open(output_file2_path, std::ifstream::binary | std::ifstream::in); + + ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); +} + +TEST_F( + ImplementationPlatformTests, + GetDownloadPath_FileNameContainsMultipleDotsReturnsIncrementBeforeFirstDot){ + // Arrange + std::ifstream input_file; + std::ofstream output_file; + + std::string file_name(kMultipleDotsFileName); + std::string renamed_file_name(kOneIterationMultipleDotsFileName); + + std::string parent_folder(""); + + std::string output_file1_path(default_download_path_); + output_file1_path.append(file_name); + + std::string output_file2_path(default_download_path_); + output_file2_path.append(renamed_file_name); + + std::string expected(default_download_path_); + expected.append(renamed_file_name); + + output_file.open(output_file1_path, + std::ofstream::binary | std::ofstream::out); + ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit); + output_file.close(); + + // Act + std::string actual = + location::nearby::api::ImplementationPlatform::GetDownloadPath( + parent_folder, file_name); + + // Assert + EXPECT_EQ(expected, actual); + + std::remove(output_file1_path.c_str()); + input_file.open(output_file1_path, std::ifstream::binary | std::ifstream::in); + + ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); +} + +TEST_F(ImplementationPlatformTests, + GetDownloadPath_FileNameContainsNoDotsReturnsWithIncrementAtEnd) { + std::ifstream input_file; + std::ofstream output_file; + + std::string file_name(kNoDotsFileName); + std::string renamed_file_name(kOneIterationNoDotsFileName); + + std::string parent_folder(""); + + std::string output_file1_path(default_download_path_); + output_file1_path.append(file_name); + + std::string output_file2_path(default_download_path_); + output_file2_path.append(renamed_file_name); + + std::string expected(default_download_path_); + expected.append(renamed_file_name); + + output_file.open(output_file1_path, + std::ofstream::binary | std::ofstream::out); + ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit); + output_file.close(); + + // Act + std::string actual = + location::nearby::api::ImplementationPlatform::GetDownloadPath( + parent_folder, file_name); + + // Assert + EXPECT_EQ(expected, actual); + + std::remove(output_file1_path.c_str()); + input_file.open(output_file1_path, std::ifstream::binary | std::ifstream::in); + + ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); +} + +TEST_F(ImplementationPlatformTests, + GetDownloadPath_FileNameExistsWithAHoleBetweenRenamedFiles) { + std::ifstream input_file; + std::ofstream output_file; + + std::string file_name(kFileName); + std::string file_name1(kFirstIterationFileName); + std::string file_name2(kSecondIterationFileName); + std::string file_name3(kThirdIterationFileName); + + std::string parent_folder(""); + + // Create the path for the original file name + std::string output_file_path(default_download_path_); + output_file_path.append( + file_name); // Original file name example: "increment_file_test.txt" + + // Create the path for the first iteration of the original file name + std::string output_file1_path(default_download_path_); + output_file1_path.append(file_name1); // First iteration on original file + // name example: + // "increment_file_test (1).txt" + + // Create the path for the third iteration of the original file name + std::string output_file3_path(default_download_path_); + output_file3_path.append( + file_name3); // Third iteration on original file + // name example: "increment_file_test (3).txt" + + // Create the expected result which is the second iteration of the original + // file name + std::string expected(default_download_path_); + expected.append(file_name2); // Second iteration on original file name + // example: "increment_file_test (2).txt" + + // Create the original file + output_file.open(output_file_path, + std::ofstream::binary | std::ofstream::out); + ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit); + output_file.close(); + + // Create the first iteration of the original file + output_file.clear(); + output_file.open(output_file1_path, + std::ofstream::binary | std::ofstream::out); + ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit); + output_file.close(); + + // Create the third iteration of the original file + output_file.clear(); + output_file.open(output_file3_path, + std::ofstream::binary | std::ofstream::out); + ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit); + output_file.close(); + + // Act + // This should return the second iteration of the original file + std::string actual = + location::nearby::api::ImplementationPlatform::GetDownloadPath( + parent_folder, file_name); + + // Assert + EXPECT_EQ(expected, actual); + + // Delete the original file + std::remove(output_file_path.c_str()); + input_file.open(output_file_path, std::ifstream::binary | std::ifstream::in); + ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); + + // Delete the first iteration of the original file + input_file.clear(); // Reset the input_file state + std::remove(output_file1_path.c_str()); + input_file.open(output_file1_path, std::ifstream::binary | std::ifstream::in); + ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); + + // Delete the third iteration of the original file + input_file.clear(); // Reset the input_file state + std::remove(output_file3_path.c_str()); + input_file.open(output_file3_path, std::ifstream::binary | std::ifstream::in); + ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); +} #endif