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
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// 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.
99bool 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.
105bool 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).
134namespace 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.
144template<typename T> struct IsMovable : base::false_type {};
145template<typename T, typename D>
146struct IsMovable<scoped_ptr<T, D> > : base::true_type {};
147
148// InType is const T& if |UseConstRef| is true, otherwise |T|.
149template<bool UseConstRef, typename T> struct InTypeHelper {
150  typedef const T& InType;
151};
152template<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.
158template<bool IsMovable, typename T> struct MoveHelper {
159  static const T& Move(const T* in) { return *in; }
160};
161template<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.
166template<typename T>
167struct 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|.
182template<typename T1>
183void 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|.
190template<typename T1, typename T2>
191void 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|.
201template<typename T1, typename T2, typename T3>
202void 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.
216template<typename T1, typename T2, typename T3, typename T4>
217struct 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.
228template<typename T1, typename T2, typename T3, typename T4>
229void 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
243template<typename T1>
244base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType)>
245CreateCopyResultCallback(T1* out1) {
246  return base::Bind(&internal::CopyResultCallback<T1>, out1);
247}
248
249template<typename T1, typename T2>
250base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType,
251                    typename internal::CopyResultCallbackHelper<T2>::InType)>
252CreateCopyResultCallback(T1* out1, T2* out2) {
253  return base::Bind(&internal::CopyResultCallback<T1, T2>, out1, out2);
254}
255
256template<typename T1, typename T2, typename T3>
257base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType,
258                    typename internal::CopyResultCallbackHelper<T2>::InType,
259                    typename internal::CopyResultCallbackHelper<T3>::InType)>
260CreateCopyResultCallback(T1* out1, T2* out2, T3* out3) {
261  return base::Bind(
262      &internal::CopyResultCallback<T1, T2, T3>, out1, out2, out3);
263}
264
265template<typename T1, typename T2, typename T3, typename T4>
266base::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)>
270CreateCopyResultCallback(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
276typedef std::pair<int64, int64> ProgressInfo;
277
278// Helper utility for recording the results via ProgressCallback.
279void AppendProgressCallbackResult(std::vector<ProgressInfo>* progress_values,
280                                  int64 progress,
281                                  int64 total);
282
283// Helper utility for recording the content via GetContentCallback.
284class 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