This adds parent path and file name to the Payload constructor. This will affect chrome.

PiperOrigin-RevId: 435223740
This commit is contained in:
jfcarroll
2022-03-16 19:18:13 -07:00
committed by Copybara-Service
parent 31b2aae6c5
commit 517d77f5aa
33 changed files with 1017 additions and 121 deletions
+2
View File
@@ -30,6 +30,7 @@ cc_windows_dll(
deps = [
"//third_party/dart_lang/v2:dart_api_dl",
"//connections:core",
"//internal/platform:base",
"//internal/platform/implementation/windows",
"//third_party/webrtc/files/stable/webrtc/api:create_peerconnection_factory",
"@com_google_absl//absl/strings",
@@ -54,6 +55,7 @@ cc_windows_dll(
deps = [
"//third_party/dart_lang/v2:dart_api_dl",
"//connections:core",
"//internal/platform:base",
"//internal/platform/implementation/windows",
"//third_party/webrtc/files/stable/webrtc/api:create_peerconnection_factory",
"@com_google_absl//absl/strings",
@@ -567,12 +567,11 @@ void SendPayloadDart(Core *pCore, const char *endpoint_id,
/*FailIfFileAlreadyExists=*/ false);
NEARBY_LOGS(INFO) << "Copy File to " << download_path;
InputFile input_file{id, payload_dart.size};
{
Payload payload{id, std::move(input_file)};
SendPayload(pCore, absl::Span<const std::string>(endpoint_ids),
std::move(payload), callback);
}
InputFile input_file(std::to_string(id), payload_dart.size);
Payload payload = Payload(id, std::move(input_file));
SendPayload(pCore, absl::Span<const std::string>(endpoint_ids),
std::move(payload), callback);
SetResultCallback(callback, result_cb);
break;
-3
View File
@@ -15,10 +15,7 @@
#define CORE_CONNECTION_OPTIONS_H_
#include <string>
#include "connections/medium_selector.h"
#include "connections/options_base.h"
#include "connections/power_level.h"
#include "connections/strategy.h"
#include "internal/platform/byte_array.h"
#include "proto/connections_enums.pb.h"
+2
View File
@@ -129,6 +129,8 @@ cc_library(
"//internal/platform:types",
"//internal/platform:util",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation/shared:file",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:btree",
@@ -42,6 +42,9 @@ class InternalPayload {
Payload::Id GetId() const;
const std::string& GetParentFolder() { return payload_.GetParentFolder(); }
const std::string& GetFileName() { return payload_.GetFileName(); }
// Returns the PayloadType of the Payload to which this object is bound.
//
// <p>Note that this is supposed to return the type from the OfflineFrame
@@ -18,13 +18,18 @@
#include <memory>
#include "absl/memory/memory.h"
#include "connections/implementation/offline_frames_validator.h"
#include "connections/payload.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/condition_variable.h"
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/file.h"
#include "internal/platform/implementation/platform.h"
#include "internal/platform/implementation/shared/file.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex.h"
#include "internal/platform/os_name.h"
#include "internal/platform/pipe.h"
namespace location {
@@ -285,6 +290,9 @@ class IncomingFileInternalPayload : public InternalPayload {
} // namespace
using location::nearby::api::ImplementationPlatform;
using location::nearby::api::OSName;
std::unique_ptr<InternalPayload> CreateOutgoingInternalPayload(
Payload payload) {
switch (payload.GetType()) {
@@ -292,10 +300,6 @@ std::unique_ptr<InternalPayload> CreateOutgoingInternalPayload(
return absl::make_unique<BytesInternalPayload>(std::move(payload));
case Payload::Type::kFile: {
InputFile* file = payload.AsFile();
const PayloadId file_payload_id = file ? file->GetPayloadId() : 0;
const PayloadId payload_id = payload.GetId();
CHECK(payload_id == file_payload_id);
return absl::make_unique<OutgoingFileInternalPayload>(std::move(payload));
}
@@ -309,6 +313,15 @@ std::unique_ptr<InternalPayload> CreateOutgoingInternalPayload(
}
}
std::string make_path(std::string& parent_folder, std::string& file_name) {
return api::ImplementationPlatform::GetDownloadPath(parent_folder, file_name);
}
std::string make_path(std::string& parent_folder, int64_t id) {
std::string file_name(std::to_string(id));
return api::ImplementationPlatform::GetDownloadPath(parent_folder, file_name);
}
std::unique_ptr<InternalPayload> CreateIncomingInternalPayload(
const PayloadTransferFrame& frame) {
if (frame.packet_type() != PayloadTransferFrame::DATA) {
@@ -334,10 +347,34 @@ std::unique_ptr<InternalPayload> CreateIncomingInternalPayload(
}
case PayloadTransferFrame::PayloadHeader::FILE: {
std::int64_t total_size = frame.payload_header().total_size();
return absl::make_unique<IncomingFileInternalPayload>(
Payload(payload_id, InputFile(payload_id, total_size)),
OutputFile(payload_id), total_size);
std::string file_path("");
int64_t total_size = 0;
if (frame.payload_header().has_parent_folder()) {
file_path = frame.payload_header().parent_folder();
}
if (frame.payload_header().has_file_name()) {
std::string file_name(frame.payload_header().file_name());
file_path = make_path(file_path, file_name);
}
if (frame.payload_header().has_total_size()) {
total_size = frame.payload_header().total_size();
}
// These are ordered, the output file must be created first otherwise
// there will be no input file to open.
// On Chrome the file path should be empty, so use the payload id.
if (ImplementationPlatform::GetCurrentOS() == OSName::kChromeOS) {
return absl::make_unique<IncomingFileInternalPayload>(
Payload(payload_id, InputFile(payload_id, total_size)),
OutputFile(payload_id), total_size);
} else {
return absl::make_unique<IncomingFileInternalPayload>(
Payload(payload_id, InputFile(file_path, total_size)),
OutputFile(file_path), total_size);
}
}
default:
DCHECK(false); // This should never happen.
@@ -58,16 +58,15 @@ TEST(InternalPayloadFActoryTest, CanCreateIternalPayloadFromStreamPayload) {
TEST(InternalPayloadFActoryTest, CanCreateIternalPayloadFromFilePayload) {
Payload::Id payload_id = Payload::GenerateId();
InputFile inputFile(payload_id, 512);
std::unique_ptr<InternalPayload> internal_payload =
CreateOutgoingInternalPayload(
Payload{payload_id, InputFile(payload_id, 512)});
CreateOutgoingInternalPayload(Payload{payload_id, std::move(inputFile)});
EXPECT_NE(internal_payload, nullptr);
Payload payload = internal_payload->ReleasePayload();
EXPECT_NE(payload.AsFile(), nullptr);
EXPECT_EQ(payload.AsStream(), nullptr);
EXPECT_EQ(payload.AsBytes(), ByteArray());
EXPECT_EQ(payload.GetId(), payload_id);
EXPECT_EQ(payload.AsFile()->GetPayloadId(), payload_id);
}
TEST(InternalPayloadFActoryTest, CanCreateIternalPayloadFromByteMessage) {
@@ -125,7 +124,6 @@ TEST(InternalPayloadFActoryTest, CanCreateIternalPayloadFromFileMessage) {
EXPECT_EQ(payload.AsStream(), nullptr);
EXPECT_EQ(payload.AsBytes(), ByteArray());
EXPECT_EQ(payload.GetType(), Payload::Type::kFile);
EXPECT_EQ(payload.GetId(), payload.AsFile()->GetPayloadId());
}
void CreateFileWithContents(Payload::Id payload_id, const ByteArray& contents) {
@@ -141,9 +139,9 @@ TEST(InternalPayloadFActoryTest,
size_t size_after_skip = contents.size() - kOffset;
Payload::Id payload_id = Payload::GenerateId();
CreateFileWithContents(payload_id, contents);
InputFile inputFile(payload_id, contents.size());
std::unique_ptr<InternalPayload> internal_payload =
CreateOutgoingInternalPayload(
Payload{payload_id, InputFile(payload_id, contents.size())});
CreateOutgoingInternalPayload(Payload{payload_id, std::move(inputFile)});
EXPECT_NE(internal_payload, nullptr);
ExceptionOr<size_t> result = internal_payload->SkipToOffset(kOffset);
@@ -16,9 +16,10 @@
#include <regex> //NOLINT
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "connections/implementation/internal_payload.h"
#include "connections/implementation/offline_frames.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "internal/platform/implementation/platform.h"
namespace location {
namespace nearby {
@@ -330,6 +331,29 @@ Exception EnsureValidBandwidthUpgradeNegotiationFrame(
return {Exception::kSuccess};
}
bool CheckForIllegalCharacters(std::string toBeValidated,
std::vector<std::string> illegalPatterns) {
if (toBeValidated.empty()) {
return false;
}
CHECK_GT(illegalPatterns.size(), 0);
return std::any_of(illegalPatterns.begin(), illegalPatterns.end(),
[&toBeValidated](const auto& s) {
size_t found = toBeValidated.find(s);
if (found != std::string::npos) {
// TODO(jfcarroll): Find a way to log messages
// here.
// NEARBY_LOGS(ERROR)
// << "Illegal character sequence found: \""
// << toBeValidated[found] << "\"";
return true;
}
return false;
});
}
} // namespace
Exception EnsureValidOfflineFrame(const OfflineFrame& offline_frame) {
@@ -352,6 +376,36 @@ Exception EnsureValidOfflineFrame(const OfflineFrame& offline_frame) {
return {Exception::kInvalidProtocolBuffer};
case V1Frame::PAYLOAD_TRANSFER:
if (offline_frame.has_v1() &&
(offline_frame.v1().payload_transfer().payload_header().has_type() &&
offline_frame.v1().payload_transfer().payload_header().type() ==
PayloadTransferFrame_PayloadHeader_PayloadType::
PayloadTransferFrame_PayloadHeader_PayloadType_FILE)) {
if (offline_frame.v1()
.payload_transfer()
.payload_header()
.has_file_name()) {
if (CheckForIllegalCharacters(offline_frame.v1()
.payload_transfer()
.payload_header()
.file_name(),
kIllegalFileNamePatterns)) {
return {Exception::kIllegalCharacters};
}
}
if (offline_frame.v1()
.payload_transfer()
.payload_header()
.has_parent_folder()) {
if (CheckForIllegalCharacters(offline_frame.v1()
.payload_transfer()
.payload_header()
.parent_folder(),
kIllegalParentFolderPatterns)) {
return {Exception::kIllegalCharacters};
}
}
}
if (offline_frame.has_v1() && offline_frame.v1().has_payload_transfer()) {
return EnsureValidPayloadTransferFrame(
offline_frame.v1().payload_transfer());
@@ -23,6 +23,23 @@ namespace nearby {
namespace connections {
namespace parser {
#ifdef NEARBY_CHROMIUM
const std::vector<std::string> kIllegalFileNamePatterns{
"/", "\\", "?", "*", "\"", "<", ">",
"|", ":", "..", "\n", "\r", "\t", "\f"};
const std::vector<std::string> kIllegalParentFolderPatterns{
"\\", "?", "*", "\"", "<", ">", "|", ":", "..", "\n", "\r", "\t", "\f"};
#else
const std::vector<std::string> kIllegalFileNamePatterns{
"/", "\\", "?", "*", "\"", "<", ">", "|", "[",
"]", ":", ",", ";", "..", "\n", "\r", "\t", "\f"};
const std::vector<std::string> kIllegalParentFolderPatterns{
"\\", "?", "*", "\"", "<", ">", "|", "[", "]",
":", ",", ";", "..", "\n", "\r", "\t", "\f"};
#endif
Exception EnsureValidOfflineFrame(const OfflineFrame& offline_frame);
} // namespace parser
@@ -213,6 +213,131 @@ TEST(OfflineFramesValidatorTest, ValidatesAsOkWithValidPayloadTransferFrame) {
ASSERT_TRUE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidatesAsOkTypeFileWithEmptyFilePathAndParent) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
// Sending files larger than 2gb was previously broken (see cl/372382338).
// This tests a file larger than int max.
header.set_total_size(3e10);
header.set_file_name(std::string());
header.set_parent_folder(std::string());
chunk.set_body("payload data");
chunk.set_offset(150);
chunk.set_flags(1);
OfflineFrame offline_frame;
ByteArray bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(std::string(bytes));
auto ret_value = EnsureValidOfflineFrame(offline_frame);
ASSERT_TRUE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest, ValidatesAsOkTypeFileWithLegalFilePath) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
// Sending files larger than 2gb was previously broken (see cl/372382338).
// This tests a file larger than int max.
header.set_total_size(3e10);
header.set_file_name(
std::string("earth_85MB_test (1) (3) (4) (8) (1) (2) (2) (1).jpg"));
header.set_parent_folder(std::string());
chunk.set_body("payload data");
chunk.set_offset(150);
chunk.set_flags(1);
OfflineFrame offline_frame;
ByteArray bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(std::string(bytes));
auto ret_value = EnsureValidOfflineFrame(offline_frame);
ASSERT_TRUE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest, ValidatesAsFailedTypeFileWithIllegalFilePath) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
// Sending files larger than 2gb was previously broken (see cl/372382338).
// This tests a file larger than int max.
header.set_total_size(3e10);
header.set_file_name(
std::string("earth_85MB_test (1): (3) (4) (8) (1) (2) (2) (1).jpg"));
header.set_parent_folder(std::string());
chunk.set_body("payload data");
chunk.set_offset(150);
chunk.set_flags(1);
OfflineFrame offline_frame;
ByteArray bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(std::string(bytes));
auto ret_value = EnsureValidOfflineFrame(offline_frame);
ASSERT_TRUE(ret_value.value == Exception::kIllegalCharacters);
}
TEST(OfflineFramesValidatorTest, ValidatesAsOkTypeFileWithLegalParentFolder) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
// Sending files larger than 2gb was previously broken (see cl/372382338).
// This tests a file larger than int max.
header.set_total_size(3e10);
header.set_file_name("");
header.set_parent_folder(std::string(
std::string("earth_85MB_test (1) (3) (4) (8) (1) (2) (2) (1).jpg")));
chunk.set_body("payload data");
chunk.set_offset(150);
chunk.set_flags(1);
OfflineFrame offline_frame;
ByteArray bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(std::string(bytes));
auto ret_value = EnsureValidOfflineFrame(offline_frame);
ASSERT_TRUE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidatesAsFailedTypeFileWithIllegalParentFolder) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
// Sending files larger than 2gb was previously broken (see cl/372382338).
// This tests a file larger than int max.
header.set_total_size(3e10);
header.set_file_name("");
header.set_parent_folder(std::string(
std::string("earth_85MB_test (1): (3) (4) (8) (1) (2) (2) (1).jpg")));
chunk.set_body("payload data");
chunk.set_offset(150);
chunk.set_flags(1);
OfflineFrame offline_frame;
ByteArray bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(std::string(bytes));
auto ret_value = EnsureValidOfflineFrame(offline_frame);
ASSERT_TRUE(ret_value.value == Exception::kIllegalCharacters);
}
TEST(OfflineFramesValidatorTest, ValidatesAsFailWithNullPayloadTransferFrame) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
+12 -2
View File
@@ -418,7 +418,10 @@ void PayloadManager::SendPayload(ClientProxy* client,
internal_payload->GetTotalSize());
PayloadTransferFrame::PayloadHeader payload_header{
CreatePayloadHeader(*internal_payload, resume_offset)};
CreatePayloadHeader(*internal_payload, resume_offset,
internal_payload->GetParentFolder(),
internal_payload->GetFileName())};
bool should_continue = true;
std::int64_t next_chunk_offset = 0;
while (should_continue && !shutdown_.Get()) {
@@ -610,12 +613,19 @@ int PayloadManager::GetOptimalChunkSize(EndpointIds endpoint_ids) {
}
PayloadTransferFrame::PayloadHeader PayloadManager::CreatePayloadHeader(
const InternalPayload& internal_payload, size_t offset) {
const InternalPayload& internal_payload, size_t offset,
const std::string& parent_folder, const std::string& file_name) {
PayloadTransferFrame::PayloadHeader payload_header;
size_t payload_size = internal_payload.GetTotalSize();
payload_header.set_id(internal_payload.GetId());
payload_header.set_type(internal_payload.GetType());
if (internal_payload.GetType() ==
location::nearby::connections::PayloadTransferFrame::PayloadHeader::
PayloadType::PayloadTransferFrame_PayloadHeader_PayloadType_FILE) {
payload_header.set_file_name(file_name);
payload_header.set_parent_folder(parent_folder);
}
payload_header.set_total_size(payload_size ==
InternalPayload::kIndeterminateSize
? InternalPayload::kIndeterminateSize
+3 -1
View File
@@ -211,7 +211,9 @@ class PayloadManager : public EndpointManager::FrameProcessor {
int GetOptimalChunkSize(EndpointIds endpoint_ids);
PayloadTransferFrame::PayloadHeader CreatePayloadHeader(
const InternalPayload& payload, size_t offset);
const InternalPayload& internal_payload, size_t offset,
const std::string& parent_folder, const std::string& file_name);
PayloadTransferFrame::PayloadChunk CreatePayloadChunk(std::int64_t offset,
ByteArray body);
+16 -7
View File
@@ -33,11 +33,19 @@ Payload::Payload(ByteArray&& bytes) : content_(std::move(bytes)) {}
Payload::Payload(const ByteArray& bytes) : content_(bytes) {}
Payload::Payload(InputFile file)
: content_(std::move(file)),
id_(std::hash<std::string>()(file.GetFilePath())) {}
Payload::Payload(InputFile input_file)
: content_(std::move(input_file)),
id_(std::hash<std::string>()(input_file.GetFilePath())) {}
Payload::Payload(Id id, InputFile input_file)
: content_(std::move(input_file)), id_(id) {}
Payload::Payload(std::string parent_folder, std::string file_name,
InputFile input_file)
: content_(std::move(input_file)),
parent_folder_(parent_folder),
file_name_(file_name) {}
// TODO(jfcarroll): Convert std::function to function pointer
Payload::Payload(std::function<InputStream&()> stream)
: content_(std::move(stream)) {}
@@ -47,9 +55,6 @@ Payload::Payload(Id id, ByteArray&& bytes)
Payload::Payload(Id id, const ByteArray& bytes) : content_(bytes), id_(id) {}
Payload::Payload(Id id, InputFile file) : content_(std::move(file)), id_(id) {}
// TODO(jfcarroll): Convert std::function to function pointer
Payload::Payload(Id id, std::function<InputStream&()> stream)
: content_(std::move(stream)), id_(id) {}
@@ -96,6 +101,10 @@ Payload::Type Payload::FindType() const {
return static_cast<Type>(content_.index());
}
const std::string& Payload::GetParentFolder() const { return parent_folder_; }
const std::string& Payload::GetFileName() const { return file_name_; }
} // namespace connections
} // namespace nearby
} // namespace location
+26 -5
View File
@@ -22,12 +22,12 @@
#include "absl/types/variant.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/payload_id.h"
#include "internal/platform/prng.h"
#include "internal/platform/core_config.h"
#include "internal/platform/file.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "internal/platform/payload_id.h"
#include "internal/platform/prng.h"
namespace location {
namespace nearby {
@@ -56,7 +56,23 @@ class DLL_API Payload {
explicit Payload(ByteArray&& bytes);
explicit Payload(const ByteArray& bytes);
explicit Payload(InputFile file);
explicit Payload(InputFile input_file);
// InputFile is just "a pointer to a file on your disc", a wrapper around a
// file name or file descriptor. It has no understanding that Nearby is going
// to create a copy of it on the remote device.
//
// FileName and ParentFolder are what Nearby is saying the remote device
// should save this incoming payload as.
//
// Notably, FileName does not have to be respected (you could ask to save it
// as "photo.png" but instead the recipient saves it as "photo (1).png").
//
// ParentFolder must be a relative path, not a full path.
explicit Payload(std::string parent_folder, std::string file_name,
InputFile file);
explicit Payload(std::function<InputStream&()> stream);
// Constructors for incoming payloads.
@@ -65,7 +81,6 @@ class DLL_API Payload {
Payload(Id id, InputFile file);
Payload(Id id, std::function<InputStream&()> stream);
// Returns ByteArray payload, if it has been defined, or empty ByteArray.
const ByteArray& AsBytes() const&;
ByteArray&& AsBytes() &&;
@@ -88,6 +103,9 @@ class DLL_API Payload {
// Generate Payload Id; to be passed to outgoing file constructor.
static Id GenerateId();
const std::string& GetFileName() const;
const std::string& GetParentFolder() const;
private:
Type FindType() const;
@@ -95,6 +113,9 @@ class DLL_API Payload {
Id id_{GenerateId()};
Type type_{FindType()};
size_t offset_{0};
std::string parent_folder_;
std::string file_name_;
};
} // namespace connections
+1
View File
@@ -35,6 +35,7 @@ cc_library(
"input_stream.h",
"listeners.h",
"nsd_service_info.h",
"os_name.h",
"output_stream.h",
"payload_id.h",
"prng.h",
+3 -1
View File
@@ -30,7 +30,9 @@ struct Exception {
kInterrupted = 2, // Operation was interrupted.
kInvalidProtocolBuffer = 3, // Couldn't parse.
kExecution = 4, // Couldn't execute.
kTimeout = 5, // Operarion did not finish within specified time.
kTimeout = 5, // Operarion did not finish within specified time.
kIllegalCharacters = 6, // File name or parent path contained
// illegal chars
};
bool Ok() const { return value == kSuccess; }
bool Raised() const { return !Ok(); }
+10 -13
View File
@@ -17,11 +17,13 @@
namespace location {
namespace nearby {
InputFile::InputFile(PayloadId payload_id, std::int64_t size)
: impl_(Platform::CreateInputFile(payload_id, size)), id_(payload_id) {}
InputFile::InputFile(PayloadId id, std::int64_t size)
: impl_(Platform::CreateInputFile(id, size)) {}
InputFile::InputFile(std::string file_path, std::int64_t size)
: impl_(Platform::CreateInputFile(file_path, size)) {}
InputFile::~InputFile() = default;
InputFile::InputFile(InputFile&&) noexcept = default;
InputFile& InputFile::operator=(InputFile&&) noexcept = default;
InputFile::InputFile(InputFile&& other) noexcept = default;
InputFile& InputFile::operator=(InputFile&& other) = default;
// Reads up to size bytes and returns as a ByteArray object wrapped by
// ExceptionOr.
@@ -53,14 +55,12 @@ Exception InputFile::Close() { return impl_->Close(); }
// versa.
InputStream& InputFile::GetInputStream() { return *impl_; }
// Returns payload id of this file. The closest "file" equivalent is inode.
PayloadId InputFile::GetPayloadId() const { return id_; }
OutputFile::OutputFile(PayloadId payload_id)
: impl_(Platform::CreateOutputFile(payload_id)), id_(payload_id) {}
OutputFile::OutputFile(std::string file_path)
: impl_(Platform::CreateOutputFile(file_path)) {}
OutputFile::OutputFile(PayloadId id) : impl_(Platform::CreateOutputFile(id)) {}
OutputFile::~OutputFile() = default;
OutputFile::OutputFile(OutputFile&&) noexcept = default;
OutputFile& OutputFile::operator=(OutputFile&&) noexcept = default;
OutputFile& OutputFile::operator=(OutputFile&&) = default;
// Writes all data from ByteArray object to the underlying stream.
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
@@ -85,8 +85,5 @@ Exception OutputFile::Close() { return impl_->Close(); }
// versa.
OutputStream& OutputFile::GetOutputStream() { return *impl_; }
// Returns payload id of this file. The closest "file" equivalent is inode.
PayloadId OutputFile::GetPayloadId() const { return id_; }
} // namespace nearby
} // namespace location
+7 -13
View File
@@ -19,14 +19,14 @@
#include <memory>
#include <string>
#include "internal/platform/byte_array.h"
#include "internal/platform/core_config.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/input_file.h"
#include "internal/platform/implementation/output_file.h"
#include "internal/platform/implementation/platform.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/core_config.h"
namespace location {
namespace nearby {
@@ -35,9 +35,10 @@ class DLL_API InputFile final {
public:
using Platform = api::ImplementationPlatform;
InputFile(PayloadId payload_id, std::int64_t size);
InputFile(std::string file_path, std::int64_t size);
~InputFile();
InputFile(InputFile&&) noexcept;
InputFile& operator=(InputFile&&) noexcept;
InputFile& operator=(InputFile&&);
// Reads up to size bytes and returns as a ByteArray object wrapped by
// ExceptionOr.
@@ -65,21 +66,18 @@ class DLL_API InputFile final {
// versa.
InputStream& GetInputStream();
// Returns payload id of this file. The closest "file" equivalent is inode.
PayloadId GetPayloadId() const;
private:
std::unique_ptr<api::InputFile> impl_;
PayloadId id_;
};
class DLL_API OutputFile final {
public:
using Platform = api::ImplementationPlatform;
explicit OutputFile(PayloadId payload_id);
explicit OutputFile(std::string file_path);
~OutputFile();
OutputFile(OutputFile&&) noexcept;
OutputFile& operator=(OutputFile&&) noexcept;
OutputFile& operator=(OutputFile&&);
// Writes all data from ByteArray object to the underlying stream.
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
@@ -102,12 +100,8 @@ class DLL_API OutputFile final {
// versa.
OutputStream& GetOutputStream();
// Returns payload id of this file. The closest "file" equivalent is inode.
PayloadId GetPayloadId() const;
private:
std::unique_ptr<api::OutputFile> impl_;
PayloadId id_;
};
} // namespace nearby
+1
View File
@@ -83,6 +83,7 @@ cc_library(
],
defines = ["NO_WEBRTC"],
visibility = [
"//connections/implementation:__subpackages__",
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//internal/platform:__pkg__",
"//internal/platform/implementation:__subpackages__",
@@ -57,11 +57,55 @@ namespace location {
namespace nearby {
namespace api {
namespace {
std::string GetPayloadPath(PayloadId payload_id) {
return absl::StrCat("/tmp/", payload_id);
std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder,
std::string& file_name) {
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();
}
} // namespace
OSName ImplementationPlatform::GetCurrentOS() { return OSName::kLinux; }
int GetCurrentTid() {
const LiveThread* my = Thread_GetMyLiveThread();
@@ -103,15 +147,33 @@ std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
return std::make_unique<g3::AtomicBoolean>(initial_value);
}
ABSL_DEPRECATED("This interface will be deleted in the near future.")
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
PayloadId payload_id, std::int64_t total_size) {
return shared::IOFile::CreateInputFile(GetPayloadPath(payload_id),
total_size);
std::string parent_folder("");
std::string file_name(std::to_string(payload_id));
return shared::IOFile::CreateInputFile(
GetDownloadPath(parent_folder, file_name), total_size);
}
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
absl::string_view file_path, size_t size) {
return shared::IOFile::CreateInputFile(file_path, size);
}
ABSL_DEPRECATED("This interface will be deleted in the near future.")
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
PayloadId payload_id) {
std::string parent_folder("");
std::string file_name(std::to_string(payload_id));
return shared::IOFile::CreateOutputFile(
GetDownloadPath(parent_folder, file_name));
}
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
PayloadId payload_id) {
return shared::IOFile::CreateOutputFile(GetPayloadPath(payload_id));
absl::string_view file_path) {
return shared::IOFile::CreateOutputFile(file_path);
}
std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
@@ -161,7 +161,8 @@ class GNCInputStreamFromNSStream : public InputStream {
PayloadId payloadId = payload.identifier;
// Add the pair of payloadId and fileURL to the map in the GNCCore.
[_core insertURLToMapWithPayloadID:payloadId urlToSend:fileURL];
Payload corePayload(payloadId, InputFile(payloadId, fileSize));
InputFile inputFile(payloadId, fileSize);
Payload corePayload(payloadId, std::move(inputFile));
progress.totalUnitCount = fileSize;
return [self sendPayload:std::move(corePayload)
size:fileSize
@@ -37,18 +37,21 @@ namespace location {
namespace nearby {
namespace api {
namespace {
std::string GetPayloadPath(PayloadId payload_id) {
std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder,
std::string& file_name) {
// This is to get a file path, e.g. /tmp/[payload_id], for the storage of payload file.
// NOTE: Per
// https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html
// Files saved in the /tmp directory will be deleted by the system. Callers should be responsible
// for copying the files to the permanent storage.
NSString* payloadIdString = ObjCStringFromCppString(std::to_string(payload_id));
// TODO(jfcarroll): This needs to be done correctly, we now have a file name and parent folder,
// they should be combined with the default download path
NSString* payloadIdString = ObjCStringFromCppString(file_name);
return CppStringFromObjCString(
[NSTemporaryDirectory() stringByAppendingPathComponent:payloadIdString]);
}
} // namespace
OSName ImplementationPlatform::GetCurrentOS() { return OSName::kiOS; }
// Atomics:
std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(bool initial_value) {
@@ -78,6 +81,7 @@ std::unique_ptr<ConditionVariable> ImplementationPlatform::CreateConditionVariab
return std::make_unique<ios::ConditionVariable>(static_cast<ios::Mutex*>(mutex));
}
ABSL_DEPRECATED("This interface will be deleted in the near future.")
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(PayloadId payload_id,
std::int64_t total_size) {
// Extract the NSURL object with payload_id from |GNCCore| which stores the maps. If the retrieved
@@ -86,14 +90,28 @@ std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(PayloadId pay
GNCCore* core = GNCGetCore();
NSURL* url = [core extractURLWithPayloadID:payload_id];
if (url != nil) {
return absl::make_unique<ios::InputFile>(url);
return std::make_unique<ios::InputFile>(url);
} else {
return shared::IOFile::CreateInputFile(GetPayloadPath(payload_id), total_size);
std::string parent_folder("");
std::string file_name(std::to_string(payload_id));
return shared::IOFile::CreateInputFile(GetDownloadPath(parent_folder, file_name), total_size);
}
}
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(absl::string_view file_path,
size_t size) {
return shared::IOFile::CreateInputFile(file_path, size);
}
ABSL_DEPRECATED("This interface will be deleted in the near future.")
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(PayloadId payload_id) {
return shared::IOFile::CreateOutputFile(GetPayloadPath(payload_id));
std::string parent_folder("");
std::string file_name(std::to_string(payload_id));
return shared::IOFile::CreateOutputFile(GetDownloadPath(parent_folder, file_name));
}
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(absl::string_view file_path) {
return shared::IOFile::CreateOutputFile(file_path);
}
std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
@@ -17,6 +17,7 @@
#import <Foundation/Foundation.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/input_file.h"
namespace location {
@@ -27,6 +28,8 @@ namespace ios {
class InputFile : public api::InputFile {
public:
explicit InputFile(NSURL *nsURL);
explicit InputFile(absl::string_view file_path, std::int64_t size);
~InputFile() override = default;
InputFile(InputFile &&) = default;
InputFile &operator=(InputFile &&) = default;
@@ -39,6 +42,9 @@ class InputFile : public api::InputFile {
private:
NSURL *nsURL_;
NSInputStream *nsStream_;
std::string path_;
size_t total_size_;
};
} // namespace ios
@@ -30,6 +30,11 @@ InputFile::InputFile(NSURL *nsURL) : nsURL_(nsURL) {
[nsStream_ open];
}
InputFile::InputFile(absl::string_view file_path, std::int64_t size)
: path_(file_path), total_size_(size) {
// TODO(jfcarroll): This is not implemented for iOS yet.
}
ExceptionOr<ByteArray> InputFile::Read(std::int64_t size) {
uint8_t *bytes_read = new uint8_t[size];
NSUInteger numberOfBytesToRead = [[NSNumber numberWithLongLong:size] unsignedIntegerValue];
+14 -3
View File
@@ -43,6 +43,7 @@
#endif
#include "internal/platform/implementation/wifi.h"
#include "internal/platform/implementation/wifi_lan.h"
#include "internal/platform/os_name.h"
#include "internal/platform/payload_id.h"
namespace location {
@@ -62,6 +63,10 @@ class ImplementationPlatform {
// - CountDownLatch : to ensure at least N threads are waiting.
// - file I/O
// - Logging
static std::string GetDownloadPath(std::string& parent_folder,
std::string& file_name);
static OSName GetCurrentOS();
// Atomics:
// =======
@@ -81,9 +86,15 @@ class ImplementationPlatform {
static std::unique_ptr<Mutex> CreateMutex(Mutex::Mode mode);
static std::unique_ptr<ConditionVariable> CreateConditionVariable(
Mutex* mutex);
static std::unique_ptr<InputFile> CreateInputFile(PayloadId payload_id,
std::int64_t total_size);
static std::unique_ptr<OutputFile> CreateOutputFile(PayloadId payload_id);
static std::unique_ptr<InputFile> CreateInputFile(PayloadId, std::int64_t);
static std::unique_ptr<InputFile> CreateInputFile(absl::string_view, size_t);
static std::unique_ptr<OutputFile> CreateOutputFile(PayloadId);
static std::unique_ptr<OutputFile> CreateOutputFile(absl::string_view);
static std::unique_ptr<LogMessage> CreateLogMessage(
const char* file, int line, LogMessage::Severity severity);
@@ -46,6 +46,7 @@ cc_library(
srcs = ["file.cc"],
hdrs = ["file.h"],
visibility = [
"//connections/implementation:__subpackages__",
"//internal/platform/implementation:__subpackages__",
],
deps = [
@@ -26,24 +26,25 @@ namespace nearby {
namespace shared {
// InputFile
std::unique_ptr<IOFile> IOFile::CreateInputFile(const absl::string_view path,
size_t size) {
return absl::WrapUnique(new IOFile(path, size));
std::unique_ptr<IOFile> IOFile::CreateInputFile(
const absl::string_view file_path, size_t size) {
return absl::WrapUnique(new IOFile(file_path, size));
}
IOFile::IOFile(const absl::string_view path, size_t size)
: file_(std::string(path.data(), path.size()),
IOFile::IOFile(const absl::string_view file_path, size_t size)
: file_(std::string(file_path.data(), file_path.size()),
std::ios::binary | std::ios::in),
path_(path),
path_(file_path),
total_size_(size) {}
std::unique_ptr<IOFile> IOFile::CreateOutputFile(const absl::string_view path) {
return std::unique_ptr<IOFile>(new IOFile(path));
}
IOFile::IOFile(const absl::string_view path)
: file_(std::string(path.data(), path.size()),
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) {}
ExceptionOr<ByteArray> IOFile::Read(std::int64_t size) {
@@ -19,9 +19,9 @@
#include <fstream>
#include "absl/strings/string_view.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/input_file.h"
#include "internal/platform/implementation/output_file.h"
#include "internal/platform/exception.h"
namespace location {
namespace nearby {
@@ -29,8 +29,9 @@ namespace shared {
class IOFile final : public api::InputFile, public api::OutputFile {
public:
static std::unique_ptr<IOFile> CreateInputFile(const absl::string_view path,
size_t size);
static std::unique_ptr<IOFile> CreateInputFile(
const absl::string_view file_path, size_t size);
static std::unique_ptr<IOFile> CreateOutputFile(const absl::string_view path);
ExceptionOr<ByteArray> Read(std::int64_t size) override;
@@ -44,10 +45,11 @@ class IOFile final : public api::InputFile, public api::OutputFile {
Exception Flush() override;
private:
explicit IOFile(const absl::string_view path, size_t size);
explicit IOFile(const absl::string_view path);
explicit IOFile(const absl::string_view file_path, size_t size);
explicit IOFile(const absl::string_view file_path);
std::fstream file_;
absl::string_view path_;
std::string path_;
std::int64_t total_size_;
};
@@ -120,7 +120,6 @@ cc_library(
"//internal/platform:types",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/shared:file",
"//internal/platform/implementation/windows/generated:types",
@@ -153,6 +152,7 @@ cc_test(
"count_down_latch_test.cc",
"crypto_test.cc",
"executor_test.cc",
"platform_test.cc",
"scheduled_executor_test.cc",
"submittable_executor_test.cc",
],
@@ -14,7 +14,12 @@
#include "internal/platform/implementation/platform.h"
#include <knownfolders.h>
#include <shlobj.h>
#include <windows.h>
#include <xstring>
#include <sstream>
#include "internal/platform/implementation/shared/count_down_latch.h"
#include "internal/platform/implementation/shared/file.h"
@@ -41,9 +46,8 @@
namespace location {
namespace nearby {
namespace api {
namespace {
std::string GetPayloadPath(PayloadId payload_id) {
std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder,
std::string& file_name) {
PWSTR basePath;
// Retrieves the full path of a known folder identified by the folder's
@@ -62,15 +66,59 @@ std::string GetPayloadPath(PayloadId payload_id) {
// SHGetKnownFolderPath succeeds or not.
size_t bufferSize;
wcstombs_s(&bufferSize, NULL, 0, basePath, 0);
char* fullpathUTF8 = new char[bufferSize + 1];
memset(fullpathUTF8, 0, bufferSize);
wcstombs_s(&bufferSize, fullpathUTF8, bufferSize, basePath, bufferSize - 1);
std::string fullPath = std::string(fullpathUTF8);
auto retval = absl::StrCat(fullPath += "\\", payload_id);
delete[] fullpathUTF8;
return retval;
std::string fullpathUTF8(bufferSize, '\0');
wcstombs_s(&bufferSize, fullpathUTF8.data(), bufferSize, basePath, _TRUNCATE);
std::string fullPath = fullpathUTF8;
// 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, 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, 1);
}
CoTaskMemFree(basePath);
std::stringstream path("");
if (parent_folder.empty() && file_name.empty()) {
return fullPath;
}
if (parent_folder.empty()) {
path << fullPath.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();
std::string retVal = path.str();
return retVal;
}
path << fullPath.c_str() << "\\" << parent_folder.c_str() << "\\"
<< file_name.c_str();
std::string retVal = path.str();
return retVal;
}
} // namespace
OSName ImplementationPlatform::GetCurrentOS() { return OSName::kWindows; }
std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
bool initial_value) {
@@ -96,15 +144,32 @@ ImplementationPlatform::CreateConditionVariable(Mutex* mutex) {
return absl::make_unique<windows::ConditionVariable>(mutex);
}
ABSL_DEPRECATED("This interface will be deleted in the near future.")
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
PayloadId payload_id, std::int64_t total_size) {
return shared::IOFile::CreateInputFile(GetPayloadPath(payload_id),
total_size);
std::string parent_folder("");
std::string file_name(std::to_string(payload_id));
return shared::IOFile::CreateInputFile(
GetDownloadPath(parent_folder, file_name), total_size);
}
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
absl::string_view file_path, size_t size) {
return shared::IOFile::CreateInputFile(file_path, size);
}
ABSL_DEPRECATED("This interface will be deleted in the near future.")
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
PayloadId payload_id) {
std::string parent_folder("");
std::string file_name(std::to_string(payload_id));
return shared::IOFile::CreateOutputFile(
GetDownloadPath(parent_folder, file_name));
}
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
PayloadId payload_id) {
return shared::IOFile::CreateOutputFile(GetPayloadPath(payload_id));
absl::string_view file_path) {
return shared::IOFile::CreateOutputFile(file_path);
}
// TODO(b/184975123): replace with real implementation.
@@ -0,0 +1,415 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/platform.h"
#include <knownfolders.h>
#include <shlobj.h>
#include <windows.h>
#include <xstring>
#include "gtest/gtest.h"
// Can't run on google 3, I presume the SHGetKnownFolderPath
// fails.
#if 0
class ImplementationPlatformTests : public testing::Test
{
protected:
// You can define per-test set-up logic as usual.
void SetUp() override
{
PWSTR basePath;
SHGetKnownFolderPath(
FOLDERID_Downloads, // rfid: A reference to the KNOWNFOLDERID that
// identifies the folder.
0, // dwFlags: Flags that specify special retrieval
// options.
NULL, // hToken: An access token that represents a
// particular user.
&basePath); // ppszPath: When this method returns, contains
// the address of a pointer to a
// null-terminated Unicode string that
// specifies the path of the known
// folder. The calling process is
// responsible for freeing this resource
// once it is no longer needed by
// calling CoTaskMemFree, whether
// SHGetKnownFolderPath succeeds or not.
size_t bufferSize;
wcstombs_s(&bufferSize, NULL, 0, basePath, 0);
std::string fullpathUTF8(bufferSize, '\0');
wcstombs_s(&bufferSize, fullpathUTF8.data(), bufferSize, basePath,
_TRUNCATE);
default_download_path_ = fullpathUTF8;
}
std::string default_download_path_;
};
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithEmptyStringArgumentsShouldReturnBaseDownloadPath)
{
// Arrange
std::string parent_folder("");
std::string file_name("");
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, default_download_path_);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithSlashParentFolderArgumentsShouldReturn\
BaseDownloadPath)
{
// Arrange
std::string parent_folder("/");
std::string file_name("");
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, default_download_path_);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithBackslashParentFolderArgumentsShouldReturn\
BaseDownloadPath)
{
// Arrange
std::string parent_folder("\\");
std::string file_name("");
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, default_download_path_);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithSlashFileNameArgumentsShouldReturnBaseDownloadPath)
{
// Arrange
std::string parent_folder("");
std::string file_name("/");
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, default_download_path_);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithBackslashFileNameArgumentsShouldReturn\
BaseDownloadPath)
{
// Arrange
std::string parent_folder("");
std::string file_name("\\");
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
auto result_size = result.size();
auto default_size = default_download_path_.size();
// Assert
EXPECT_EQ(result, default_download_path_);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithParentFolderShouldReturnParentFolder\
AppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("test_parent_folder");
std::string file_name("");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "test_parent_folder";
std::string expected = path.str();
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, expected);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithParentFolderStartingWithSlashArgumentsShouldReturn\
ParentFolderAppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("/test_parent_folder");
std::string file_name("");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "test_parent_folder";
std::string expected = path.str();
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, expected);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithParentFolderStartingWithBackslashArguments\
ShouldReturnParentFolderAppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("\\test_parent_folder");
std::string file_name("");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "test_parent_folder";
std::string expected = path.str();
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, expected);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithParentFolderEndingWithSlashArgumentsShouldReturn\
ParentFolderAppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("test_parent_folder/");
std::string file_name("");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "test_parent_folder";
std::string expected = path.str();
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, expected);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithParentFolderEndingWithBackslashArguments\
ShouldReturnParentFolderAppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("test_parent_folder\\");
std::string file_name("");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "test_parent_folder";
std::string expected = path.str();
// Act
auto result = location::nearby::api::ImplementationPlatform::GetDownloadPath(
parent_folder, file_name);
// Assert
EXPECT_EQ(result, expected);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithFileNameBeginningWithSlashArgumentsShouldReturn\
FileNameAppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("");
std::string file_name("/test_file_name.name");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "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);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithFileNameBeginningWithBackslashArgumentsShouldReturn\
FileNameAppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("");
std::string file_name("\\test_file_name.name");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "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);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithFileNameEndingWithSlashArgumentsShouldReturnFileName\
AppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("");
std::string file_name("test_file_name.name/");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "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);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithFileNameEndingWithBackslashArgumentsShouldReturn\
FileNameAppendedToBaseDownloadPath)
{
// Arrange
std::string parent_folder("");
std::string file_name("test_file_name.name\\");
std::stringstream path("");
path << default_download_path_.c_str() << "\\"
<< "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);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithParentFolderAndFileNameArgumentsShouldReturn\
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() << "\\"
<< "test_parent_folder"
<< "\\"
<< "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);
}
TEST_F(ImplementationPlatformTests,
GetDownloadPathWithParentFolderEndingWithBackslashAndFileNameArguments\
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() << "\\"
<< "test_parent_folder"
<< "\\"
<< "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);
}
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() << "\\"
<< "test_parent_folder"
<< "\\"
<< "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);
}
#endif
@@ -16,6 +16,8 @@
#include <shlobj.h>
#include <sstream>
#include "absl/strings/str_cat.h"
namespace test_utils {
@@ -49,13 +51,21 @@ std::string GetPayloadPath(location::nearby::PayloadId payload_id) {
// SHGetKnownFolderPath succeeds or not.
size_t bufferSize;
// Get the required buffer size.
wcstombs_s(&bufferSize, NULL, 0, basePath, 0);
char* fullpathUTF8 = new char[bufferSize + 1];
memset(fullpathUTF8, 0, bufferSize);
wcstombs_s(&bufferSize, fullpathUTF8, bufferSize, basePath, bufferSize - 1);
std::string fullpathUTF8(bufferSize, NULL);
wcstombs_s(&bufferSize, fullpathUTF8.data(), bufferSize, basePath, _TRUNCATE);
std::string fullPath = std::string(fullpathUTF8);
auto retval = absl::StrCat(fullPath += "\\", payload_id);
delete[] fullpathUTF8;
// Clean up the string by removing null's
fullPath.erase(std::find(fullPath.begin(), fullPath.end(), '\0'),
fullPath.end());
CoTaskMemFree(basePath);
std::stringstream path("");
path << fullPath << "\\" << std::to_string(payload_id);
auto retval = path.str();
return retval;
}
} // namespace test_utils
+28
View File
@@ -0,0 +1,28 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_OS_NAME_H_
#define PLATFORM_OS_NAME_H_
namespace location {
namespace nearby {
namespace api {
enum class OSName { kLinux, kWindows, kiOS, kChromeOS };
} // namespace api
} // namespace nearby
} // namespace location
#endif // PLATFORM_OS_NAME_H_