Chromium Code Reviews| Index: chrome/browser/google_apis/test_util.h |
| diff --git a/chrome/browser/google_apis/test_util.h b/chrome/browser/google_apis/test_util.h |
| index d76f360114ee36f398b5e28d052c56381f5815bc..125551f3b397ce89cc790ab808fd4759661226b6 100644 |
| --- a/chrome/browser/google_apis/test_util.h |
| +++ b/chrome/browser/google_apis/test_util.h |
| @@ -7,7 +7,10 @@ |
| #include <string> |
| +#include "base/bind.h" |
| +#include "base/callback.h" |
| #include "base/memory/scoped_ptr.h" |
| +#include "base/template_util.h" |
| #include "chrome/browser/google_apis/gdata_errorcode.h" |
| class GURL; |
| @@ -43,6 +46,9 @@ namespace test_util { |
| // repeatedly. |
| void RunBlockingPoolTask(); |
| +// Runs the closure, and then quits the current MessageLoop. |
| +void RunAndQuit(const base::Closure& closure); |
| + |
| // Removes |prefix| from |input| and stores the result in |output|. Returns |
| // true if the prefix is removed. |
| bool RemovePrefix(const std::string& input, |
| @@ -185,6 +191,130 @@ bool ParseContentRangeHeader(const std::string& value, |
| 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, ...)); |
| +// RunBlockingPoolTask(); // 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 3. The limitation comes |
| +// from the max arity of base::Callback, which is 7. A created callback |
| +// consumes two arguments for each input type. |
| +// TODO(hidehiko): Use replace CopyResultFromXxxCallback method defined above |
| +// by this one. (crbug.com/180569). |
| +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 operation 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 |
| + // The incoming type is as follows: |
| + // 1) If argument type |T| is non-class type or supporting Chrome's Move |
| + // concept, |InType| is |T| as is. |
| + // 2) Otherwise, const T&. |
| + : InTypeHelper<base::is_class<T>::value && !IsMovable<T>::value, T>, |
|
hashimoto
2013/03/13 06:27:52
nit: Please add a comment about that this boolean
hidehiko
2013/03/13 08:49:19
Done. Also, swapped the condition in the comment 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); |
| +} |
| + |
| +} // 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); |
| +} |
| + |
| } // namespace test_util |
| } // namespace google_apis |