Skip to content

StorageReference List stubs #1733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: feature/storagereference_list
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions storage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ set(android_SRCS
src/android/controller_android.cc
src/android/metadata_android.cc
src/android/storage_android.cc
src/android/storage_reference_android.cc)
src/android/storage_reference_android.cc
src/android/list_result_android.cc)

# Source files used by the iOS implementation.
set(ios_SRCS
Expand All @@ -47,7 +48,8 @@ set(ios_SRCS
src/ios/metadata_ios.mm
src/ios/storage_ios.mm
src/ios/storage_reference_ios.mm
src/ios/util_ios.mm)
src/ios/util_ios.mm
src/ios/list_result_ios.mm)

# Source files used by the desktop implementation.
set(desktop_SRCS
Expand All @@ -58,7 +60,8 @@ set(desktop_SRCS
src/desktop/rest_operation.cc
src/desktop/storage_desktop.cc
src/desktop/storage_path.cc
src/desktop/storage_reference_desktop.cc)
src/desktop/storage_reference_desktop.cc
src/desktop/list_result_desktop.cc)

if(ANDROID)
set(storage_platform_SRCS
Expand Down
72 changes: 72 additions & 0 deletions storage/integration_test/src/integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "firebase/auth.h"
#include "firebase/internal/platform.h"
#include "firebase/storage.h"
#include "firebase/storage/list_result.h"
#include "firebase/util.h"
#include "firebase_test_framework.h" // NOLINT

Expand Down Expand Up @@ -1622,4 +1623,75 @@ TEST_F(FirebaseStorageTest, TestInvalidatingReferencesWhenDeletingApp) {
InitializeAppAndAuth();
}

// Test the StorageReference::ListAll() method.
// This test currently only verifies that the stubbed method returns an empty result.
TEST_F(FirebaseStorageTest, TestListAll) {
if (skip_tests_) return;

firebase::storage::Storage* storage = storage_; // Use the member variable
firebase::storage::StorageReference reference = storage->GetReference();

firebase::Future<firebase::storage::ListResult> future = reference.ListAll();
WaitForCompletion(future, "ListAll");

ASSERT_EQ(future.status(), firebase::kFutureStatusComplete);
ASSERT_EQ(future.error(), firebase::storage::kErrorNone);

const firebase::storage::ListResult* result = future.result();
ASSERT_NE(result, nullptr);
if (result != nullptr) {
EXPECT_TRUE(result->items.empty());
EXPECT_TRUE(result->prefixes.empty());
EXPECT_TRUE(result->page_token.empty());
}
}

// Test the StorageReference::List() method with no page token.
// This test currently only verifies that the stubbed method returns an empty result.
TEST_F(FirebaseStorageTest, TestListNoPageToken) {
if (skip_tests_) return;

firebase::storage::Storage* storage = storage_; // Use the member variable
firebase::storage::StorageReference reference = storage->GetReference();

firebase::Future<firebase::storage::ListResult> future = reference.List();
WaitForCompletion(future, "List (no page token)");

ASSERT_EQ(future.status(), firebase::kFutureStatusComplete);
ASSERT_EQ(future.error(), firebase::storage::kErrorNone);

const firebase::storage::ListResult* result = future.result();
ASSERT_NE(result, nullptr);
if (result != nullptr) {
EXPECT_TRUE(result->items.empty());
EXPECT_TRUE(result->prefixes.empty());
EXPECT_TRUE(result->page_token.empty());
}
}

// Test the StorageReference::List() method with a page token.
// This test currently only verifies that the stubbed method returns an empty result
// and that the page token is passed (though not used by the stub).
TEST_F(FirebaseStorageTest, TestListWithPageToken) {
if (skip_tests_) return;

firebase::storage::Storage* storage = storage_; // Use the member variable
firebase::storage::StorageReference reference = storage->GetReference();
const char* page_token = "test_page_token";

firebase::Future<firebase::storage::ListResult> future = reference.List(page_token);
WaitForCompletion(future, "List (with page token)");

ASSERT_EQ(future.status(), firebase::kFutureStatusComplete);
ASSERT_EQ(future.error(), firebase::storage::kErrorNone);

const firebase::storage::ListResult* result = future.result();
ASSERT_NE(result, nullptr);
if (result != nullptr) {
EXPECT_TRUE(result->items.empty());
EXPECT_TRUE(result->prefixes.empty());
EXPECT_TRUE(result->page_token.empty());
}
}

} // namespace firebase_testapp_automated
21 changes: 21 additions & 0 deletions storage/src/android/list_result_android.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// File: storage/src/android/list_result_android.cc
#include "storage/src/android/list_result_android.h"

namespace firebase {
namespace storage {
namespace internal {

ListResultInternal::ListResultInternal(
StorageReferenceInternal* platform_sri,
const ListResultInternal* other_to_copy_from)
: platform_sri_(platform_sri) {
if (other_to_copy_from) {
items_ = other_to_copy_from->items_;
prefixes_ = other_to_copy_from->prefixes_;
page_token_ = other_to_copy_from->page_token_;
}
}

} // namespace internal
} // namespace storage
} // namespace firebase
46 changes: 46 additions & 0 deletions storage/src/android/list_result_android.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// File: storage/src/android/list_result_android.h
#ifndef FIREBASE_STORAGE_CLIENT_CPP_SRC_ANDROID_LIST_RESULT_ANDROID_H_
#define FIREBASE_STORAGE_CLIENT_CPP_SRC_ANDROID_LIST_RESULT_ANDROID_H_

#include <string>
#include <vector>

#include "firebase/storage/storage_reference.h"
#include "storage/src/android/storage_reference_android.h" // Defines firebase::storage::internal::StorageReferenceInternal for android
#include "storage/src/android/storage_internal_android.h" // Defines firebase::storage::internal::StorageInternal for android

namespace firebase {
namespace storage {
namespace internal {

class ListResultInternal {
public:
explicit ListResultInternal(
StorageReferenceInternal* platform_sri,
const ListResultInternal* other_to_copy_from = nullptr);

const std::vector<StorageReference>& items() const { return items_; }
const std::vector<StorageReference>& prefixes() const { return prefixes_; }
const std::string& page_token() const { return page_token_; }

StorageReferenceInternal* storage_reference_internal() const {
return platform_sri_;
}
StorageInternal* associated_storage_internal() const {
return platform_sri_ ? platform_sri_->storage_internal() : nullptr;
}

private:
ListResultInternal& operator=(const ListResultInternal&);

StorageReferenceInternal* platform_sri_;
std::vector<StorageReference> items_;
std::vector<StorageReference> prefixes_;
std::string page_token_;
};

} // namespace internal
} // namespace storage
} // namespace firebase

#endif // FIREBASE_STORAGE_CLIENT_CPP_SRC_ANDROID_LIST_RESULT_ANDROID_H_
1 change: 1 addition & 0 deletions storage/src/android/storage_reference_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "app/src/include/firebase/app.h"
#include "app/src/util_android.h"
#include "storage/src/android/controller_android.h"
// Removed: #include "storage/src/android/list_result_android.h"
#include "storage/src/android/metadata_android.h"
#include "storage/src/android/storage_android.h"
#include "storage/src/include/firebase/storage.h"
Expand Down
1 change: 1 addition & 0 deletions storage/src/android/storage_reference_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "app/src/reference_counted_future_impl.h"
#include "app/src/util_android.h"
#include "storage/src/android/storage_android.h"
// Removed: #include "storage/src/common/list_result_internal.h"
#include "storage/src/include/firebase/storage/storage_reference.h"

namespace firebase {
Expand Down
195 changes: 195 additions & 0 deletions storage/src/common/list_result.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// File: storage/src/common/list_result.cc

#include "firebase/storage/list_result.h" // For ListResult public class
#include "app/src/include/firebase/internal/platform.h" // For FIREBASE_PLATFORM defines
#include "app/src/cleanup_notifier.h" // For CleanupNotifier
#include "app/src/log.h" // For LogDebug, LogWarning
#include "firebase/storage/storage_reference.h" // For StorageReference (used by ListResult members)

// Platform-specific headers that define internal::ListResultInternal (the PIMPL class)
// and internal::StorageInternal (for CleanupNotifier context).
#if FIREBASE_PLATFORM_ANDROID
#include "storage/src/android/list_result_android.h"
#include "storage/src/android/storage_internal_android.h"
#elif FIREBASE_PLATFORM_IOS || FIREBASE_PLATFORM_TVOS
#include "storage/src/ios/list_result_ios.h"
#include "storage/src/ios/storage_internal_ios.h"
#else // Desktop
#include "storage/src/desktop/list_result_desktop.h"
#include "storage/src/desktop/storage_internal_desktop.h"
#endif


namespace firebase {
namespace storage {

// Forward declaration of the PIMPL class.
namespace internal {
class ListResultInternal;
class StorageReferenceInternal;
class StorageInternal;
} // namespace internal

namespace internal {

// ListResultInternalCommon: Provides static helper methods for managing the
// lifecycle of the ListResultInternal PIMPL object.
class ListResultInternalCommon {
public:
// Retrieves the StorageInternal context from the ListResultInternal object.
static StorageInternal* GetStorageInternalContext(
ListResultInternal* pimpl_obj) {
if (!pimpl_obj) return nullptr;
// Relies on ListResultInternal having associated_storage_internal().
StorageInternal* storage_ctx = pimpl_obj->associated_storage_internal();
if (storage_ctx == nullptr) {
LogWarning("ListResultInternal %p has no associated StorageInternal for cleanup.", pimpl_obj);
}
return storage_ctx;
}

// Callback for CleanupNotifier, invoked when the App is being destroyed.
static void CleanupPublicListResultObject(void* public_obj_void) {
ListResult* public_obj = reinterpret_cast<ListResult*>(public_obj_void);
if (public_obj) {
LogDebug("CleanupNotifier: Cleaning up ListResult %p.", public_obj);
DeleteInternalPimpl(public_obj);
} else {
LogWarning("CleanupNotifier: CleanupPublicListResultObject called with null object.");
}
}

static void RegisterForCleanup(ListResult* public_obj,
ListResultInternal* pimpl_obj) {
FIREBASE_ASSERT(public_obj != nullptr);
if (!pimpl_obj) return;
StorageInternal* storage_ctx = GetStorageInternalContext(pimpl_obj);
if (storage_ctx) {
storage_ctx->cleanup().RegisterObject(public_obj, CleanupPublicListResultObject);
LogDebug("ListResult %p (PIMPL %p) registered for cleanup.",
public_obj, pimpl_obj);
} else {
LogWarning("Could not register ListResult %p for cleanup: no StorageInternal context.",
public_obj);
}
}

static void UnregisterFromCleanup(ListResult* public_obj,
ListResultInternal* pimpl_obj) {
FIREBASE_ASSERT(public_obj != nullptr);
if (!pimpl_obj) return;
StorageInternal* storage_ctx = GetStorageInternalContext(pimpl_obj);
if (storage_ctx) {
storage_ctx->cleanup().UnregisterObject(public_obj);
LogDebug("ListResult %p (associated with PIMPL %p) unregistered from cleanup.",
public_obj, pimpl_obj);
} else {
LogWarning("Could not unregister ListResult %p: no StorageInternal context.", public_obj);
}
}

// Deletes the PIMPL object, unregisters from cleanup, and nulls the pointer in public_obj.
static void DeleteInternalPimpl(ListResult* public_obj) {
FIREBASE_ASSERT(public_obj != nullptr);
if (!public_obj->internal_) return;

ListResultInternal* pimpl_to_delete = public_obj->internal_;
UnregisterFromCleanup(public_obj, pimpl_to_delete);
public_obj->internal_ = nullptr;
delete pimpl_to_delete;
}
};

} // namespace internal

// --- Public ListResult Method Implementations ---

const std::vector<StorageReference> ListResult::s_empty_items_;
const std::vector<StorageReference> ListResult::s_empty_prefixes_;
const std::string ListResult::s_empty_page_token_;

ListResult::ListResult() : internal_(nullptr) {
}

ListResult::ListResult(internal::ListResultInternal* internal_pimpl)
: internal_(internal_pimpl) {
if (internal_) {
internal::ListResultInternalCommon::RegisterForCleanup(this, internal_);
}
}

ListResult::~ListResult() {
internal::ListResultInternalCommon::DeleteInternalPimpl(this);
}

ListResult::ListResult(const ListResult& other) : internal_(nullptr) {
if (other.internal_) {
internal::StorageReferenceInternal* sri_context =
other.internal_->storage_reference_internal();
internal_ = new internal::ListResultInternal(sri_context, other.internal_);
internal::ListResultInternalCommon::RegisterForCleanup(this, internal_);
}
}

ListResult& ListResult::operator=(const ListResult& other) {
if (this == &other) {
return *this;
}
internal::ListResultInternalCommon::DeleteInternalPimpl(this); // Clean up current

if (other.internal_) {
internal::StorageReferenceInternal* sri_context =
other.internal_->storage_reference_internal();
internal_ = new internal::ListResultInternal(sri_context, other.internal_);
internal::ListResultInternalCommon::RegisterForCleanup(this, internal_);
}
return *this;
}

#if defined(FIREBASE_USE_MOVE_OPERATORS) || defined(DOXYGEN)
ListResult::ListResult(ListResult&& other) : internal_(other.internal_) {
other.internal_ = nullptr;
if (internal_) {
// New public object 'this' takes ownership. Unregister 'other', register 'this'.
internal::ListResultInternalCommon::UnregisterFromCleanup(&other, internal_);
internal::ListResultInternalCommon::RegisterForCleanup(this, internal_);
}
}

ListResult& ListResult::operator=(ListResult&& other) {
if (this == &other) {
return *this;
}
internal::ListResultInternalCommon::DeleteInternalPimpl(this); // Clean up current

internal_ = other.internal_;
other.internal_ = nullptr;

if (internal_) {
// Similar to move constructor: unregister 'other', register 'this'.
internal::ListResultInternalCommon::UnregisterFromCleanup(&other, internal_);
internal::ListResultInternalCommon::RegisterForCleanup(this, internal_);
}
return *this;
}
#endif // defined(FIREBASE_USE_MOVE_OPERATORS) || defined(DOXYGEN)

const std::vector<StorageReference>& ListResult::items() const {
if (!is_valid()) return s_empty_items_;
return internal_->items();
}

const std::vector<StorageReference>& ListResult::prefixes() const {
if (!is_valid()) return s_empty_prefixes_;
return internal_->prefixes();
}

const std::string& ListResult::page_token() const {
if (!is_valid()) return s_empty_page_token_;
return internal_->page_token();
}

bool ListResult::is_valid() const { return internal_ != nullptr; }

} // namespace storage
} // namespace firebase
Loading
Loading