// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/fileapi/test/fake_recent_source.h"
#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include "base/containers/extend.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ash/fileapi/recent_file.h"
#include "fake_recent_source.h"
#include "net/base/mime_util.h"
namespace ash {
// Helper method for matching file type against the desired `file_type`.
bool MatchesFileType(const RecentFile& file, RecentSource::FileType file_type) {
if (file_type == RecentSource::FileType::kAll) {
return true;
}
std::string mime_type;
if (!net::GetMimeTypeFromFile(file.url().path(), &mime_type)) {
return false;
}
switch (file_type) {
case RecentSource::FileType::kAudio:
return net::MatchesMimeType("audio/*", mime_type);
case RecentSource::FileType::kImage:
return net::MatchesMimeType("image/*", mime_type);
case RecentSource::FileType::kVideo:
return net::MatchesMimeType("video/*", mime_type);
default:
return false;
}
}
FileProducer::FileProducer(const base::TimeDelta& lag,
std::vector<RecentFile> files)
: lag_(lag), files_(std::move(files)) {}
FileProducer::~FileProducer() = default;
void FileProducer::GetFiles(RecentSource::GetRecentFilesCallback callback) {
timers_.emplace_back(std::make_unique<base::OneShotTimer>());
timers_.back()->Start(
FROM_HERE, lag_,
base::BindOnce(&FileProducer::OnFilesReady, base::Unretained(this),
std::move(callback)));
}
void FileProducer::OnFilesReady(RecentSource::GetRecentFilesCallback callback) {
std::move(callback).Run(files_);
}
FakeRecentSource::CallContext::CallContext(GetRecentFilesCallback callback,
const Params& params)
: callback(std::move(callback)), params(params) {}
FakeRecentSource::CallContext::CallContext(CallContext&& context)
: callback(std::move(context.callback)),
params(context.params),
accumulator(std::move(context.accumulator)),
active_producer_count(context.active_producer_count) {}
FakeRecentSource::CallContext::~CallContext() = default;
FakeRecentSource::FakeRecentSource()
: FakeRecentSource(
extensions::api::file_manager_private::VolumeType::kTesting) {}
FakeRecentSource::FakeRecentSource(
extensions::api::file_manager_private::VolumeType volume_type)
: RecentSource(volume_type) {}
FakeRecentSource::~FakeRecentSource() = default;
void FakeRecentSource::AddProducer(std::unique_ptr<FileProducer> producer) {
producers_.emplace_back(std::move(producer));
}
void FakeRecentSource::GetRecentFiles(const Params& params,
GetRecentFilesCallback callback) {
const auto& [it, _] = context_map_.emplace(
params.call_id(), CallContext(std::move(callback), params));
if (producers_.empty()) {
OnAllProducersDone(params.call_id());
return;
}
it->second.active_producer_count = producers_.size();
for (const auto& producer : producers_) {
producer->GetFiles(base::BindOnce(&FakeRecentSource::OnProducerReady,
base::Unretained(this),
params.call_id()));
}
}
std::vector<RecentFile> FakeRecentSource::Stop(const int32_t call_id) {
auto it = context_map_.find(call_id);
if (it == context_map_.end()) {
LOG(INFO) << "Received files after results delivered to recent model";
return {};
}
std::vector<RecentFile> files =
GetMatchingFiles(it->second.accumulator, it->second.params);
context_map_.erase(it);
return files;
}
void FakeRecentSource::OnProducerReady(const int32_t call_id,
std::vector<RecentFile> files) {
auto it = context_map_.find(call_id);
if (it == context_map_.end()) {
LOG(INFO) << "Producer ready after source stopped";
return;
}
base::Extend(it->second.accumulator, files);
if (--it->second.active_producer_count <= 0) {
OnAllProducersDone(call_id);
}
}
void FakeRecentSource::OnAllProducersDone(int32_t call_id) {
auto it = context_map_.find(call_id);
if (it == context_map_.end()) {
LOG(WARNING) << "FakeRecentSource ready after it was stopped";
return;
}
std::move(it->second.callback)
.Run(GetMatchingFiles(it->second.accumulator, it->second.params));
context_map_.erase(it);
}
std::vector<RecentFile> FakeRecentSource::GetMatchingFiles(
const std::vector<RecentFile>& accumulator,
const Params& params) {
const std::u16string q16 = base::UTF8ToUTF16(params.query());
std::vector<RecentFile> result;
for (const auto& file : accumulator) {
if (!MatchesFileType(file, params.file_type())) {
continue;
}
if (!FileNameMatches(file.url().path().LossyDisplayName(), q16)) {
continue;
}
result.push_back(file);
}
return result;
}
} // namespace ash