• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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>
CreateQuitCallback(base::RunLoop * run_loop,const CallbackType & callback)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 // Parses a value of Content-Range header, which looks like
97 // "bytes <start_position>-<end_position>/<length>".
98 // Returns true on success.
99 bool 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.
126 namespace 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.
136 template<typename T> struct IsMovable : base::false_type {};
137 template<typename T, typename D>
138 struct IsMovable<scoped_ptr<T, D> > : base::true_type {};
139 
140 // InType is const T& if |UseConstRef| is true, otherwise |T|.
141 template<bool UseConstRef, typename T> struct InTypeHelper {
142   typedef const T& InType;
143 };
144 template<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.
150 template<bool IsMovable, typename T> struct MoveHelper {
151   static const T& Move(const T* in) { return *in; }
152 };
153 template<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.
158 template<typename T>
159 struct 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|.
174 template<typename T1>
175 void 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|.
182 template<typename T1, typename T2>
183 void 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|.
193 template<typename T1, typename T2, typename T3>
194 void 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.
208 template<typename T1, typename T2, typename T3, typename T4>
209 struct 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.
220 template<typename T1, typename T2, typename T3, typename T4>
221 void 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 
235 template<typename T1>
236 base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType)>
237 CreateCopyResultCallback(T1* out1) {
238   return base::Bind(&internal::CopyResultCallback<T1>, out1);
239 }
240 
241 template<typename T1, typename T2>
242 base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType,
243                     typename internal::CopyResultCallbackHelper<T2>::InType)>
244 CreateCopyResultCallback(T1* out1, T2* out2) {
245   return base::Bind(&internal::CopyResultCallback<T1, T2>, out1, out2);
246 }
247 
248 template<typename T1, typename T2, typename T3>
249 base::Callback<void(typename internal::CopyResultCallbackHelper<T1>::InType,
250                     typename internal::CopyResultCallbackHelper<T2>::InType,
251                     typename internal::CopyResultCallbackHelper<T3>::InType)>
252 CreateCopyResultCallback(T1* out1, T2* out2, T3* out3) {
253   return base::Bind(
254       &internal::CopyResultCallback<T1, T2, T3>, out1, out2, out3);
255 }
256 
257 template<typename T1, typename T2, typename T3, typename T4>
258 base::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)>
262 CreateCopyResultCallback(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 
268 typedef std::pair<int64, int64> ProgressInfo;
269 
270 // Helper utility for recording the results via ProgressCallback.
271 void AppendProgressCallbackResult(std::vector<ProgressInfo>* progress_values,
272                                   int64 progress,
273                                   int64 total);
274 
275 // Helper utility for recording the content via GetContentCallback.
276 class 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