1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef GOOGLE_APIS_DRIVE_TEST_UTIL_H_ 6#define GOOGLE_APIS_DRIVE_TEST_UTIL_H_ 7 8#include <string> 9#include <utility> 10#include <vector> 11 12#include "base/bind.h" 13#include "base/callback.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/memory/scoped_vector.h" 16#include "base/template_util.h" 17#include "google_apis/drive/base_requests.h" 18#include "google_apis/drive/gdata_errorcode.h" 19#include "google_apis/drive/task_util.h" 20 21class GURL; 22 23namespace base { 24class FilePath; 25class RunLoop; 26class Value; 27} 28 29namespace net { 30namespace test_server { 31class BasicHttpResponse; 32class HttpResponse; 33struct HttpRequest; 34} 35} 36 37namespace google_apis { 38namespace test_util { 39 40// Runs the closure, and then quits the |run_loop|. 41void RunAndQuit(base::RunLoop* run_loop, const base::Closure& closure); 42 43// Returns callback which runs the given |callback| and then quits |run_loop|. 44template<typename CallbackType> 45CallbackType CreateQuitCallback(base::RunLoop* run_loop, 46 const CallbackType& callback) { 47 return CreateComposedCallback(base::Bind(&RunAndQuit, run_loop), callback); 48} 49 50// Removes |prefix| from |input| and stores the result in |output|. Returns 51// true if the prefix is removed. 52bool RemovePrefix(const std::string& input, 53 const std::string& prefix, 54 std::string* output); 55 56// Returns the absolute path for a test file stored under 57// chrome/test/data. 58base::FilePath GetTestFilePath(const std::string& relative_path); 59 60// Returns the base URL for communicating with the local test server for 61// testing, running at the specified port number. 62GURL GetBaseUrlForTesting(int port); 63 64// Writes the |content| to the file at |file_path|. Returns true on success, 65// otherwise false. 66bool WriteStringToFile(const base::FilePath& file_path, 67 const std::string& content); 68 69// Creates a |size| byte file. The file is filled with random bytes so that 70// the test assertions can identify correct portion/position of the file is 71// used. 72// Returns true on success with the created file's |path| and |data|, otherwise 73// false. 74bool CreateFileOfSpecifiedSize(const base::FilePath& temp_dir, 75 size_t size, 76 base::FilePath* path, 77 std::string* data); 78 79// Loads a test JSON file as a base::Value, from a test file stored under 80// chrome/test/data. 81scoped_ptr<base::Value> LoadJSONFile(const std::string& relative_path); 82 83// Returns a HttpResponse created from the given file path. 84scoped_ptr<net::test_server::BasicHttpResponse> CreateHttpResponseFromFile( 85 const base::FilePath& file_path); 86 87// Handles a request for downloading a file. Reads a file from the test 88// directory and returns the content. Also, copies the |request| to the memory 89// pointed by |out_request|. 90// |base_url| must be set to the server's base url. 91scoped_ptr<net::test_server::HttpResponse> HandleDownloadFileRequest( 92 const GURL& base_url, 93 net::test_server::HttpRequest* out_request, 94 const net::test_server::HttpRequest& request); 95 96// Parses a value of Content-Range header, which looks like 97// "bytes <start_position>-<end_position>/<length>". 98// Returns true on success. 99bool ParseContentRangeHeader(const std::string& value, 100 int64* start_position, 101 int64* end_position, 102 int64* length); 103 104// Google API related code and Drive File System code work on asynchronous 105// architecture and return the results via callbacks. 106// Following code implements a callback to copy such results. 107// Here is how to use: 108// 109// // Prepare result storage. 110// ResultType1 result1; 111// ResultType2 result2; 112// : 113// 114// PerformAsynchronousTask( 115// param1, param2, ..., 116// CreateCopyResultCallback(&result1, &result2, ...)); 117// base::RunLoop().RunUntilIdle(); // Run message loop to complete 118// // the async task. 119// 120// // Hereafter, we can write expectation with results. 121// EXPECT_EQ(expected_result1, result1); 122// EXPECT_EQ(expected_result2, result2); 123// : 124// 125// Note: The max arity of the supported function is 4 based on the usage. 126namespace internal { 127// Following helper templates are to support Chrome's move semantics. 128// Their goal is defining helper methods which are similar to: 129// void CopyResultCallback1(T1* out1, T1&& in1) 130// void CopyResultCallback2(T1* out1, T2* out2, T1&& in1, T2&& in2) 131// : 132// in C++11. 133 134// Declare if the type is movable or not. Currently limited to scoped_ptr only. 135// We can add more types upon the usage. 136template<typename T> struct IsMovable : base::false_type {}; 137template<typename T, typename D> 138struct IsMovable<scoped_ptr<T, D> > : base::true_type {}; 139 140// InType is const T& if |UseConstRef| is true, otherwise |T|. 141template<bool UseConstRef, typename T> struct InTypeHelper { 142 typedef const T& InType; 143}; 144template<typename T> struct InTypeHelper<false, T> { 145 typedef T InType; 146}; 147 148// Simulates the std::move function in C++11. We use pointer here for argument, 149// instead of rvalue reference. 150template<bool IsMovable, typename T> struct MoveHelper { 151 static const T& Move(const T* in) { return *in; } 152}; 153template<typename T> struct MoveHelper<true, T> { 154 static T Move(T* in) { return in->Pass(); } 155}; 156 157// Helper to handle Chrome's move semantics correctly. 158template<typename T> 159struct CopyResultCallbackHelper 160 // It is necessary to calculate the exact signature of callbacks we want 161 // to create here. In our case, as we use value-parameters for primitive 162 // types and movable types in the callback declaration. 163 // Thus the incoming type is as follows: 164 // 1) If the argument type |T| is class type but doesn't movable, 165 // |InType| is const T&. 166 // 2) Otherwise, |T| as is. 167 : InTypeHelper< 168 base::is_class<T>::value && !IsMovable<T>::value, // UseConstRef 169 T>, 170 MoveHelper<IsMovable<T>::value, T> { 171}; 172 173// Copies the |in|'s value to |out|. 174template<typename T1> 175void CopyResultCallback( 176 T1* out, 177 typename CopyResultCallbackHelper<T1>::InType in) { 178 *out = CopyResultCallbackHelper<T1>::Move(&in); 179} 180 181// Copies the |in1|'s value to |out1|, and |in2|'s to |out2|. 182template<typename T1, typename T2> 183void CopyResultCallback( 184 T1* out1, 185 T2* out2, 186 typename CopyResultCallbackHelper<T1>::InType in1, 187 typename CopyResultCallbackHelper<T2>::InType in2) { 188 *out1 = CopyResultCallbackHelper<T1>::Move(&in1); 189 *out2 = CopyResultCallbackHelper<T2>::Move(&in2); 190} 191 192// Copies the |in1|'s value to |out1|, |in2|'s to |out2|, and |in3|'s to |out3|. 193template<typename T1, typename T2, typename T3> 194void CopyResultCallback( 195 T1* out1, 196 T2* out2, 197 T3* out3, 198 typename CopyResultCallbackHelper<T1>::InType in1, 199 typename CopyResultCallbackHelper<T2>::InType in2, 200 typename CopyResultCallbackHelper<T3>::InType in3) { 201 *out1 = CopyResultCallbackHelper<T1>::Move(&in1); 202 *out2 = CopyResultCallbackHelper<T2>::Move(&in2); 203 *out3 = CopyResultCallbackHelper<T3>::Move(&in3); 204} 205 206// Holds the pointers for output. This is introduced for the workaround of 207// the arity limitation of Callback. 208template<typename T1, typename T2, typename T3, typename T4> 209struct OutputParams { 210 OutputParams(T1* out1, T2* out2, T3* out3, T4* out4) 211 : out1(out1), out2(out2), out3(out3), out4(out4) {} 212 T1* out1; 213 T2* out2; 214 T3* out3; 215 T4* out4; 216}; 217 218// Copies the |in1|'s value to |output->out1|, |in2|'s to |output->out2|, 219// and so on. 220template<typename T1, typename T2, typename T3, typename T4> 221void CopyResultCallback( 222 const OutputParams<T1, T2, T3, T4>& output, 223 typename CopyResultCallbackHelper<T1>::InType in1, 224 typename CopyResultCallbackHelper<T2>::InType in2, 225 typename CopyResultCallbackHelper<T3>::InType in3, 226 typename CopyResultCallbackHelper<T4>::InType in4) { 227 *output.out1 = CopyResultCallbackHelper<T1>::Move(&in1); 228 *output.out2 = CopyResultCallbackHelper<T2>::Move(&in2); 229 *output.out3 = CopyResultCallbackHelper<T3>::Move(&in3); 230 *output.out4 = CopyResultCallbackHelper<T4>::Move(&in4); 231} 232 233} // namespace internal 234 235template<typename T1> 236base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType)> 237CreateCopyResultCallback(T1* out1) { 238 return base::Bind(&internal::CopyResultCallback<T1>, out1); 239} 240 241template<typename T1, typename T2> 242base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType, 243 typename internal::CopyResultCallbackHelper<T2>::InType)> 244CreateCopyResultCallback(T1* out1, T2* out2) { 245 return base::Bind(&internal::CopyResultCallback<T1, T2>, out1, out2); 246} 247 248template<typename T1, typename T2, typename T3> 249base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType, 250 typename internal::CopyResultCallbackHelper<T2>::InType, 251 typename internal::CopyResultCallbackHelper<T3>::InType)> 252CreateCopyResultCallback(T1* out1, T2* out2, T3* out3) { 253 return base::Bind( 254 &internal::CopyResultCallback<T1, T2, T3>, out1, out2, out3); 255} 256 257template<typename T1, typename T2, typename T3, typename T4> 258base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType, 259 typename internal::CopyResultCallbackHelper<T2>::InType, 260 typename internal::CopyResultCallbackHelper<T3>::InType, 261 typename internal::CopyResultCallbackHelper<T4>::InType)> 262CreateCopyResultCallback(T1* out1, T2* out2, T3* out3, T4* out4) { 263 return base::Bind( 264 &internal::CopyResultCallback<T1, T2, T3, T4>, 265 internal::OutputParams<T1, T2, T3, T4>(out1, out2, out3, out4)); 266} 267 268typedef std::pair<int64, int64> ProgressInfo; 269 270// Helper utility for recording the results via ProgressCallback. 271void AppendProgressCallbackResult(std::vector<ProgressInfo>* progress_values, 272 int64 progress, 273 int64 total); 274 275// Helper utility for recording the content via GetContentCallback. 276class TestGetContentCallback { 277 public: 278 TestGetContentCallback(); 279 ~TestGetContentCallback(); 280 281 const GetContentCallback& callback() const { return callback_; } 282 const ScopedVector<std::string>& data() const { return data_; } 283 ScopedVector<std::string>* mutable_data() { return &data_; } 284 std::string GetConcatenatedData() const; 285 286 private: 287 void OnGetContent(google_apis::GDataErrorCode error, 288 scoped_ptr<std::string> data); 289 290 const GetContentCallback callback_; 291 ScopedVector<std::string> data_; 292 293 DISALLOW_COPY_AND_ASSIGN(TestGetContentCallback); 294}; 295 296} // namespace test_util 297} // namespace google_apis 298 299#endif // GOOGLE_APIS_DRIVE_TEST_UTIL_H_ 300