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 CHROME_BROWSER_GOOGLE_APIS_TEST_UTIL_H_ 6 #define CHROME_BROWSER_GOOGLE_APIS_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 "chrome/browser/google_apis/base_requests.h" 18 #include "chrome/browser/google_apis/gdata_errorcode.h" 19 #include "chrome/browser/google_apis/task_util.h" 20 21 class GURL; 22 23 namespace base { 24 class FilePath; 25 class RunLoop; 26 class Value; 27 } 28 29 namespace net { 30 namespace test_server { 31 class BasicHttpResponse; 32 class HttpResponse; 33 struct HttpRequest; 34 } 35 } 36 37 namespace google_apis { 38 namespace test_util { 39 40 // Runs the closure, and then quits the |run_loop|. 41 void RunAndQuit(base::RunLoop* run_loop, const base::Closure& closure); 42 43 // Returns callback which runs the given |callback| and then quits |run_loop|. 44 template<typename CallbackType> 45 CallbackType 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. 52 bool 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. 58 base::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. 62 GURL GetBaseUrlForTesting(int port); 63 64 // Writes the |content| to the file at |file_path|. Returns true on success, 65 // otherwise false. 66 bool 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. 74 bool 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. 81 scoped_ptr<base::Value> LoadJSONFile(const std::string& relative_path); 82 83 // Returns a HttpResponse created from the given file path. 84 scoped_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. 91 scoped_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 // Returns true if |json_data| is not NULL and equals to the content in 97 // |expected_json_file_path|. The failure reason will be logged into LOG(ERROR) 98 // if necessary. 99 bool VerifyJsonData(const base::FilePath& expected_json_file_path, 100 const base::Value* json_data); 101 102 // Parses a value of Content-Range header, which looks like 103 // "bytes <start_position>-<end_position>/<length>". 104 // Returns true on success. 105 bool ParseContentRangeHeader(const std::string& value, 106 int64* start_position, 107 int64* end_position, 108 int64* length); 109 110 // Google API related code and Drive File System code work on asynchronous 111 // architecture and return the results via callbacks. 112 // Following code implements a callback to copy such results. 113 // Here is how to use: 114 // 115 // // Prepare result storage. 116 // ResultType1 result1; 117 // ResultType2 result2; 118 // : 119 // 120 // PerformAsynchronousTask( 121 // param1, param2, ..., 122 // CreateCopyResultCallback(&result1, &result2, ...)); 123 // base::RunLoop().RunUntilIdle(); // Run message loop to complete 124 // // the async task. 125 // 126 // // Hereafter, we can write expectation with results. 127 // EXPECT_EQ(expected_result1, result1); 128 // EXPECT_EQ(expected_result2, result2); 129 // : 130 // 131 // Note: The max arity of the supported function is 4 based on the usage. 132 // TODO(hidehiko): Use replace CopyResultFromXxxCallback method defined above 133 // by this one. (crbug.com/180569). 134 namespace internal { 135 // Following helper templates are to support Chrome's move semantics. 136 // Their goal is defining helper methods which are similar to: 137 // void CopyResultCallback1(T1* out1, T1&& in1) 138 // void CopyResultCallback2(T1* out1, T2* out2, T1&& in1, T2&& in2) 139 // : 140 // in C++11. 141 142 // Declare if the type is movable or not. Currently limited to scoped_ptr only. 143 // We can add more types upon the usage. 144 template<typename T> struct IsMovable : base::false_type {}; 145 template<typename T, typename D> 146 struct IsMovable<scoped_ptr<T, D> > : base::true_type {}; 147 148 // InType is const T& if |UseConstRef| is true, otherwise |T|. 149 template<bool UseConstRef, typename T> struct InTypeHelper { 150 typedef const T& InType; 151 }; 152 template<typename T> struct InTypeHelper<false, T> { 153 typedef T InType; 154 }; 155 156 // Simulates the std::move function in C++11. We use pointer here for argument, 157 // instead of rvalue reference. 158 template<bool IsMovable, typename T> struct MoveHelper { 159 static const T& Move(const T* in) { return *in; } 160 }; 161 template<typename T> struct MoveHelper<true, T> { 162 static T Move(T* in) { return in->Pass(); } 163 }; 164 165 // Helper to handle Chrome's move semantics correctly. 166 template<typename T> 167 struct CopyResultCallbackHelper 168 // It is necessary to calculate the exact signature of callbacks we want 169 // to create here. In our case, as we use value-parameters for primitive 170 // types and movable types in the callback declaration. 171 // Thus the incoming type is as follows: 172 // 1) If the argument type |T| is class type but doesn't movable, 173 // |InType| is const T&. 174 // 2) Otherwise, |T| as is. 175 : InTypeHelper< 176 base::is_class<T>::value && !IsMovable<T>::value, // UseConstRef 177 T>, 178 MoveHelper<IsMovable<T>::value, T> { 179 }; 180 181 // Copies the |in|'s value to |out|. 182 template<typename T1> 183 void CopyResultCallback( 184 T1* out, 185 typename CopyResultCallbackHelper<T1>::InType in) { 186 *out = CopyResultCallbackHelper<T1>::Move(&in); 187 } 188 189 // Copies the |in1|'s value to |out1|, and |in2|'s to |out2|. 190 template<typename T1, typename T2> 191 void CopyResultCallback( 192 T1* out1, 193 T2* out2, 194 typename CopyResultCallbackHelper<T1>::InType in1, 195 typename CopyResultCallbackHelper<T2>::InType in2) { 196 *out1 = CopyResultCallbackHelper<T1>::Move(&in1); 197 *out2 = CopyResultCallbackHelper<T2>::Move(&in2); 198 } 199 200 // Copies the |in1|'s value to |out1|, |in2|'s to |out2|, and |in3|'s to |out3|. 201 template<typename T1, typename T2, typename T3> 202 void CopyResultCallback( 203 T1* out1, 204 T2* out2, 205 T3* out3, 206 typename CopyResultCallbackHelper<T1>::InType in1, 207 typename CopyResultCallbackHelper<T2>::InType in2, 208 typename CopyResultCallbackHelper<T3>::InType in3) { 209 *out1 = CopyResultCallbackHelper<T1>::Move(&in1); 210 *out2 = CopyResultCallbackHelper<T2>::Move(&in2); 211 *out3 = CopyResultCallbackHelper<T3>::Move(&in3); 212 } 213 214 // Holds the pointers for output. This is introduced for the workaround of 215 // the arity limitation of Callback. 216 template<typename T1, typename T2, typename T3, typename T4> 217 struct OutputParams { 218 OutputParams(T1* out1, T2* out2, T3* out3, T4* out4) 219 : out1(out1), out2(out2), out3(out3), out4(out4) {} 220 T1* out1; 221 T2* out2; 222 T3* out3; 223 T4* out4; 224 }; 225 226 // Copies the |in1|'s value to |output->out1|, |in2|'s to |output->out2|, 227 // and so on. 228 template<typename T1, typename T2, typename T3, typename T4> 229 void CopyResultCallback( 230 const OutputParams<T1, T2, T3, T4>& output, 231 typename CopyResultCallbackHelper<T1>::InType in1, 232 typename CopyResultCallbackHelper<T2>::InType in2, 233 typename CopyResultCallbackHelper<T3>::InType in3, 234 typename CopyResultCallbackHelper<T4>::InType in4) { 235 *output.out1 = CopyResultCallbackHelper<T1>::Move(&in1); 236 *output.out2 = CopyResultCallbackHelper<T2>::Move(&in2); 237 *output.out3 = CopyResultCallbackHelper<T3>::Move(&in3); 238 *output.out4 = CopyResultCallbackHelper<T4>::Move(&in4); 239 } 240 241 } // namespace internal 242 243 template<typename T1> 244 base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType)> 245 CreateCopyResultCallback(T1* out1) { 246 return base::Bind(&internal::CopyResultCallback<T1>, out1); 247 } 248 249 template<typename T1, typename T2> 250 base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType, 251 typename internal::CopyResultCallbackHelper<T2>::InType)> 252 CreateCopyResultCallback(T1* out1, T2* out2) { 253 return base::Bind(&internal::CopyResultCallback<T1, T2>, out1, out2); 254 } 255 256 template<typename T1, typename T2, typename T3> 257 base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType, 258 typename internal::CopyResultCallbackHelper<T2>::InType, 259 typename internal::CopyResultCallbackHelper<T3>::InType)> 260 CreateCopyResultCallback(T1* out1, T2* out2, T3* out3) { 261 return base::Bind( 262 &internal::CopyResultCallback<T1, T2, T3>, out1, out2, out3); 263 } 264 265 template<typename T1, typename T2, typename T3, typename T4> 266 base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType, 267 typename internal::CopyResultCallbackHelper<T2>::InType, 268 typename internal::CopyResultCallbackHelper<T3>::InType, 269 typename internal::CopyResultCallbackHelper<T4>::InType)> 270 CreateCopyResultCallback(T1* out1, T2* out2, T3* out3, T4* out4) { 271 return base::Bind( 272 &internal::CopyResultCallback<T1, T2, T3, T4>, 273 internal::OutputParams<T1, T2, T3, T4>(out1, out2, out3, out4)); 274 } 275 276 typedef std::pair<int64, int64> ProgressInfo; 277 278 // Helper utility for recording the results via ProgressCallback. 279 void AppendProgressCallbackResult(std::vector<ProgressInfo>* progress_values, 280 int64 progress, 281 int64 total); 282 283 // Helper utility for recording the content via GetContentCallback. 284 class TestGetContentCallback { 285 public: 286 TestGetContentCallback(); 287 ~TestGetContentCallback(); 288 289 const GetContentCallback& callback() const { return callback_; } 290 const ScopedVector<std::string>& data() const { return data_; } 291 ScopedVector<std::string>* mutable_data() { return &data_; } 292 std::string GetConcatenatedData() const; 293 294 private: 295 void OnGetContent(google_apis::GDataErrorCode error, 296 scoped_ptr<std::string> data); 297 298 const GetContentCallback callback_; 299 ScopedVector<std::string> data_; 300 301 DISALLOW_COPY_AND_ASSIGN(TestGetContentCallback); 302 }; 303 304 } // namespace test_util 305 } // namespace google_apis 306 307 #endif // CHROME_BROWSER_GOOGLE_APIS_TEST_UTIL_H_ 308