blob: 4672f537fa6d18efd53b6b45cd9a7755d208fe20 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GOOGLE_APIS_DRIVE_TEST_UTIL_H_
#define GOOGLE_APIS_DRIVE_TEST_UTIL_H_
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/template_util.h"
#include "google_apis/drive/base_requests.h"
#include "google_apis/drive/drive_api_error_codes.h"
#include "google_apis/drive/task_util.h"
class GURL;
namespace base {
class FilePath;
class RunLoop;
class Value;
}
namespace net {
namespace test_server {
class BasicHttpResponse;
class HttpResponse;
struct HttpRequest;
}
}
namespace google_apis {
namespace test_util {
// Runs the closure, and then quits the |run_loop|.
void RunAndQuit(base::RunLoop* run_loop, const base::Closure& closure);
// Returns callback which runs the given |callback| and then quits |run_loop|.
template<typename CallbackType>
CallbackType CreateQuitCallback(base::RunLoop* run_loop,
const CallbackType& callback) {
return CreateComposedCallback(base::Bind(&RunAndQuit, run_loop), callback);
}
// Removes |prefix| from |input| and stores the result in |output|. Returns
// true if the prefix is removed.
bool RemovePrefix(const std::string& input,
const std::string& prefix,
std::string* output);
// Returns the absolute path for a test file stored under
// chrome/test/data.
base::FilePath GetTestFilePath(const std::string& relative_path);
// Returns the base URL for communicating with the local test server for
// testing, running at the specified port number.
GURL GetBaseUrlForTesting(int port);
// Writes the |content| to the file at |file_path|. Returns true on success,
// otherwise false.
bool WriteStringToFile(const base::FilePath& file_path,
const std::string& content);
// Creates a |size| byte file. The file is filled with random bytes so that
// the test assertions can identify correct portion/position of the file is
// used.
// Returns true on success with the created file's |path| and |data|, otherwise
// false.
bool CreateFileOfSpecifiedSize(const base::FilePath& temp_dir,
size_t size,
base::FilePath* path,
std::string* data);
// Loads a test JSON file as a base::Value, from a test file stored under
// chrome/test/data.
scoped_ptr<base::Value> LoadJSONFile(const std::string& relative_path);
// Returns a HttpResponse created from the given file path.
scoped_ptr<net::test_server::BasicHttpResponse> CreateHttpResponseFromFile(
const base::FilePath& file_path);
// Handles a request for downloading a file. Reads a file from the test
// directory and returns the content. Also, copies the |request| to the memory
// pointed by |out_request|.
// |base_url| must be set to the server's base url.
scoped_ptr<net::test_server::HttpResponse> HandleDownloadFileRequest(
const GURL& base_url,
net::test_server::HttpRequest* out_request,
const net::test_server::HttpRequest& request);
// Parses a value of Content-Range header, which looks like
// "bytes <start_position>-<end_position>/<length>".
// Returns true on success.
bool ParseContentRangeHeader(const std::string& value,
int64* start_position,
int64* end_position,
int64* length);
// Google API related code and Drive File System code work on asynchronous
// architecture and return the results via callbacks.
// Following code implements a callback to copy such results.
// Here is how to use:
//
// // Prepare result storage.
// ResultType1 result1;
// ResultType2 result2;
// :
//
// PerformAsynchronousTask(
// param1, param2, ...,
// CreateCopyResultCallback(&result1, &result2, ...));
// base::RunLoop().RunUntilIdle(); // Run message loop to complete
// // the async task.
//
// // Hereafter, we can write expectation with results.
// EXPECT_EQ(expected_result1, result1);
// EXPECT_EQ(expected_result2, result2);
// :
//
// Note: The max arity of the supported function is 4 based on the usage.
namespace internal {
// Following helper templates are to support Chrome's move semantics.
// Their goal is defining helper methods which are similar to:
// void CopyResultCallback1(T1* out1, T1&& in1)
// void CopyResultCallback2(T1* out1, T2* out2, T1&& in1, T2&& in2)
// :
// in C++11.
// Declare if the type is movable or not. Currently limited to scoped_ptr only.
// We can add more types upon the usage.
template<typename T> struct IsMovable : base::false_type {};
template<typename T, typename D>
struct IsMovable<scoped_ptr<T, D> > : base::true_type {};
// InType is const T& if |UseConstRef| is true, otherwise |T|.
template<bool UseConstRef, typename T> struct InTypeHelper {
typedef const T& InType;
};
template<typename T> struct InTypeHelper<false, T> {
typedef T InType;
};
// Simulates the std::move function in C++11. We use pointer here for argument,
// instead of rvalue reference.
template<bool IsMovable, typename T> struct MoveHelper {
static const T& Move(const T* in) { return *in; }
};
template<typename T> struct MoveHelper<true, T> {
static T Move(T* in) { return in->Pass(); }
};
// Helper to handle Chrome's move semantics correctly.
template<typename T>
struct CopyResultCallbackHelper
// It is necessary to calculate the exact signature of callbacks we want
// to create here. In our case, as we use value-parameters for primitive
// types and movable types in the callback declaration.
// Thus the incoming type is as follows:
// 1) If the argument type |T| is class type but doesn't movable,
// |InType| is const T&.
// 2) Otherwise, |T| as is.
: InTypeHelper<
base::is_class<T>::value && !IsMovable<T>::value, // UseConstRef
T>,
MoveHelper<IsMovable<T>::value, T> {
};
// Copies the |in|'s value to |out|.
template<typename T1>
void CopyResultCallback(
T1* out,
typename CopyResultCallbackHelper<T1>::InType in) {
*out = CopyResultCallbackHelper<T1>::Move(&in);
}
// Copies the |in1|'s value to |out1|, and |in2|'s to |out2|.
template<typename T1, typename T2>
void CopyResultCallback(
T1* out1,
T2* out2,
typename CopyResultCallbackHelper<T1>::InType in1,
typename CopyResultCallbackHelper<T2>::InType in2) {
*out1 = CopyResultCallbackHelper<T1>::Move(&in1);
*out2 = CopyResultCallbackHelper<T2>::Move(&in2);
}
// Copies the |in1|'s value to |out1|, |in2|'s to |out2|, and |in3|'s to |out3|.
template<typename T1, typename T2, typename T3>
void CopyResultCallback(
T1* out1,
T2* out2,
T3* out3,
typename CopyResultCallbackHelper<T1>::InType in1,
typename CopyResultCallbackHelper<T2>::InType in2,
typename CopyResultCallbackHelper<T3>::InType in3) {
*out1 = CopyResultCallbackHelper<T1>::Move(&in1);
*out2 = CopyResultCallbackHelper<T2>::Move(&in2);
*out3 = CopyResultCallbackHelper<T3>::Move(&in3);
}
// Holds the pointers for output. This is introduced for the workaround of
// the arity limitation of Callback.
template<typename T1, typename T2, typename T3, typename T4>
struct OutputParams {
OutputParams(T1* out1, T2* out2, T3* out3, T4* out4)
: out1(out1), out2(out2), out3(out3), out4(out4) {}
T1* out1;
T2* out2;
T3* out3;
T4* out4;
};
// Copies the |in1|'s value to |output->out1|, |in2|'s to |output->out2|,
// and so on.
template<typename T1, typename T2, typename T3, typename T4>
void CopyResultCallback(
const OutputParams<T1, T2, T3, T4>& output,
typename CopyResultCallbackHelper<T1>::InType in1,
typename CopyResultCallbackHelper<T2>::InType in2,
typename CopyResultCallbackHelper<T3>::InType in3,
typename CopyResultCallbackHelper<T4>::InType in4) {
*output.out1 = CopyResultCallbackHelper<T1>::Move(&in1);
*output.out2 = CopyResultCallbackHelper<T2>::Move(&in2);
*output.out3 = CopyResultCallbackHelper<T3>::Move(&in3);
*output.out4 = CopyResultCallbackHelper<T4>::Move(&in4);
}
} // namespace internal
template<typename T1>
base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType)>
CreateCopyResultCallback(T1* out1) {
return base::Bind(&internal::CopyResultCallback<T1>, out1);
}
template<typename T1, typename T2>
base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType,
typename internal::CopyResultCallbackHelper<T2>::InType)>
CreateCopyResultCallback(T1* out1, T2* out2) {
return base::Bind(&internal::CopyResultCallback<T1, T2>, out1, out2);
}
template<typename T1, typename T2, typename T3>
base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType,
typename internal::CopyResultCallbackHelper<T2>::InType,
typename internal::CopyResultCallbackHelper<T3>::InType)>
CreateCopyResultCallback(T1* out1, T2* out2, T3* out3) {
return base::Bind(
&internal::CopyResultCallback<T1, T2, T3>, out1, out2, out3);
}
template<typename T1, typename T2, typename T3, typename T4>
base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType,
typename internal::CopyResultCallbackHelper<T2>::InType,
typename internal::CopyResultCallbackHelper<T3>::InType,
typename internal::CopyResultCallbackHelper<T4>::InType)>
CreateCopyResultCallback(T1* out1, T2* out2, T3* out3, T4* out4) {
return base::Bind(
&internal::CopyResultCallback<T1, T2, T3, T4>,
internal::OutputParams<T1, T2, T3, T4>(out1, out2, out3, out4));
}
typedef std::pair<int64, int64> ProgressInfo;
// Helper utility for recording the results via ProgressCallback.
void AppendProgressCallbackResult(std::vector<ProgressInfo>* progress_values,
int64 progress,
int64 total);
// Helper utility for recording the content via GetContentCallback.
class TestGetContentCallback {
public:
TestGetContentCallback();
~TestGetContentCallback();
const GetContentCallback& callback() const { return callback_; }
const ScopedVector<std::string>& data() const { return data_; }
ScopedVector<std::string>* mutable_data() { return &data_; }
std::string GetConcatenatedData() const;
private:
void OnGetContent(google_apis::DriveApiErrorCode error,
scoped_ptr<std::string> data);
const GetContentCallback callback_;
ScopedVector<std::string> data_;
DISALLOW_COPY_AND_ASSIGN(TestGetContentCallback);
};
} // namespace test_util
} // namespace google_apis
#endif // GOOGLE_APIS_DRIVE_TEST_UTIL_H_