// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef GOOGLE_APIS_DRIVE_TEST_UTIL_H_ #define GOOGLE_APIS_DRIVE_TEST_UTIL_H_ #include #include #include #include #include #include "base/bind.h" #include "base/callback.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "base/template_util.h" #include "google_apis/drive/base_requests.h" #include "google_apis/drive/drive_api_error_codes.h" #include "google_apis/drive/task_util.h" class GURL; namespace base { class FilePath; class RunLoop; class Value; } namespace net { namespace test_server { class BasicHttpResponse; class HttpResponse; struct HttpRequest; } } namespace google_apis { namespace test_util { // Runs the closure, and then quits the |run_loop|. void RunAndQuit(base::RunLoop* run_loop, const base::Closure& closure); // Returns callback which runs the given |callback| and then quits |run_loop|. template CallbackType CreateQuitCallback(base::RunLoop* run_loop, const CallbackType& callback) { return CreateComposedCallback(base::Bind(&RunAndQuit, run_loop), callback); } // Removes |prefix| from |input| and stores the result in |output|. Returns // true if the prefix is removed. bool RemovePrefix(const std::string& input, const std::string& prefix, std::string* output); // Returns the absolute path for a test file stored under // chrome/test/data. base::FilePath GetTestFilePath(const std::string& relative_path); // Returns the base URL for communicating with the local test server for // testing, running at the specified port number. GURL GetBaseUrlForTesting(int port); // Writes the |content| to the file at |file_path|. Returns true on success, // otherwise false. bool WriteStringToFile(const base::FilePath& file_path, const std::string& content); // Creates a |size| byte file. The file is filled with random bytes so that // the test assertions can identify correct portion/position of the file is // used. // Returns true on success with the created file's |path| and |data|, otherwise // false. bool CreateFileOfSpecifiedSize(const base::FilePath& temp_dir, size_t size, base::FilePath* path, std::string* data); // Loads a test JSON file as a base::Value, from a test file stored under // chrome/test/data. scoped_ptr LoadJSONFile(const std::string& relative_path); // Returns a HttpResponse created from the given file path. scoped_ptr CreateHttpResponseFromFile( const base::FilePath& file_path); // Handles a request for downloading a file. Reads a file from the test // directory and returns the content. Also, copies the |request| to the memory // pointed by |out_request|. // |base_url| must be set to the server's base url. scoped_ptr HandleDownloadFileRequest( const GURL& base_url, net::test_server::HttpRequest* out_request, const net::test_server::HttpRequest& request); // Parses a value of Content-Range header, which looks like // "bytes -/". // Returns true on success. bool ParseContentRangeHeader(const std::string& value, int64_t* start_position, int64_t* end_position, int64_t* 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, ...)); // base::RunLoop().RunUntilIdle(); // 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 4 based on the usage. 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 struct IsMovable : base::false_type {}; template struct IsMovable > : base::true_type {}; // InType is const T& if |UseConstRef| is true, otherwise |T|. template struct InTypeHelper { typedef const T& InType; }; template struct InTypeHelper { typedef T InType; }; // Simulates the std::move function in C++11. We use pointer here for argument, // instead of rvalue reference. template struct MoveHelper { static const T& Move(const T* in) { return *in; } }; template struct MoveHelper { static T Move(T* in) { return in->Pass(); } }; // Helper to handle Chrome's move semantics correctly. template struct CopyResultCallbackHelper // It is necessary to calculate the exact signature of callbacks we want // to create here. In our case, as we use value-parameters for primitive // types and movable types in the callback declaration. // Thus the incoming type is as follows: // 1) If the argument type |T| is class type but doesn't movable, // |InType| is const T&. // 2) Otherwise, |T| as is. : InTypeHelper< base::is_class::value && !IsMovable::value, // UseConstRef T>, MoveHelper::value, T> { }; // Copies the |in|'s value to |out|. template void CopyResultCallback( T1* out, typename CopyResultCallbackHelper::InType in) { *out = CopyResultCallbackHelper::Move(&in); } // Copies the |in1|'s value to |out1|, and |in2|'s to |out2|. template void CopyResultCallback( T1* out1, T2* out2, typename CopyResultCallbackHelper::InType in1, typename CopyResultCallbackHelper::InType in2) { *out1 = CopyResultCallbackHelper::Move(&in1); *out2 = CopyResultCallbackHelper::Move(&in2); } // Copies the |in1|'s value to |out1|, |in2|'s to |out2|, and |in3|'s to |out3|. template void CopyResultCallback( T1* out1, T2* out2, T3* out3, typename CopyResultCallbackHelper::InType in1, typename CopyResultCallbackHelper::InType in2, typename CopyResultCallbackHelper::InType in3) { *out1 = CopyResultCallbackHelper::Move(&in1); *out2 = CopyResultCallbackHelper::Move(&in2); *out3 = CopyResultCallbackHelper::Move(&in3); } // Holds the pointers for output. This is introduced for the workaround of // the arity limitation of Callback. template struct OutputParams { OutputParams(T1* out1, T2* out2, T3* out3, T4* out4) : out1(out1), out2(out2), out3(out3), out4(out4) {} T1* out1; T2* out2; T3* out3; T4* out4; }; // Copies the |in1|'s value to |output->out1|, |in2|'s to |output->out2|, // and so on. template void CopyResultCallback( const OutputParams& output, typename CopyResultCallbackHelper::InType in1, typename CopyResultCallbackHelper::InType in2, typename CopyResultCallbackHelper::InType in3, typename CopyResultCallbackHelper::InType in4) { *output.out1 = CopyResultCallbackHelper::Move(&in1); *output.out2 = CopyResultCallbackHelper::Move(&in2); *output.out3 = CopyResultCallbackHelper::Move(&in3); *output.out4 = CopyResultCallbackHelper::Move(&in4); } } // namespace internal template base::Callback::InType)> CreateCopyResultCallback(T1* out1) { return base::Bind(&internal::CopyResultCallback, out1); } template base::Callback::InType, typename internal::CopyResultCallbackHelper::InType)> CreateCopyResultCallback(T1* out1, T2* out2) { return base::Bind(&internal::CopyResultCallback, out1, out2); } template base::Callback::InType, typename internal::CopyResultCallbackHelper::InType, typename internal::CopyResultCallbackHelper::InType)> CreateCopyResultCallback(T1* out1, T2* out2, T3* out3) { return base::Bind( &internal::CopyResultCallback, out1, out2, out3); } template base::Callback::InType, typename internal::CopyResultCallbackHelper::InType, typename internal::CopyResultCallbackHelper::InType, typename internal::CopyResultCallbackHelper::InType)> CreateCopyResultCallback(T1* out1, T2* out2, T3* out3, T4* out4) { return base::Bind( &internal::CopyResultCallback, internal::OutputParams(out1, out2, out3, out4)); } typedef std::pair ProgressInfo; // Helper utility for recording the results via ProgressCallback. void AppendProgressCallbackResult(std::vector* progress_values, int64_t progress, int64_t total); // Helper utility for recording the content via GetContentCallback. class TestGetContentCallback { public: TestGetContentCallback(); ~TestGetContentCallback(); const GetContentCallback& callback() const { return callback_; } const ScopedVector& data() const { return data_; } ScopedVector* mutable_data() { return &data_; } std::string GetConcatenatedData() const; private: void OnGetContent(google_apis::DriveApiErrorCode error, scoped_ptr data); const GetContentCallback callback_; ScopedVector data_; DISALLOW_COPY_AND_ASSIGN(TestGetContentCallback); }; } // namespace test_util } // namespace google_apis #endif // GOOGLE_APIS_DRIVE_TEST_UTIL_H_