// Copyright 2013 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. #include "content/child/fileapi/webfilewriter_base.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebFileError.h" #include "third_party/WebKit/public/platform/WebFileWriterClient.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "url/gurl.h" namespace content { namespace { // We use particular offsets to trigger particular behaviors // in the TestableFileWriter. const int kNoOffset = -1; const int kBasicFileTruncate_Offset = 1; const int kErrorFileTruncate_Offset = 2; const int kCancelFileTruncate_Offset = 3; const int kCancelFailedTruncate_Offset = 4; const int kBasicFileWrite_Offset = 1; const int kErrorFileWrite_Offset = 2; const int kMultiFileWrite_Offset = 3; const int kCancelFileWriteBeforeCompletion_Offset = 4; const int kCancelFileWriteAfterCompletion_Offset = 5; GURL mock_path_as_gurl() { return GURL("MockPath"); } } // namespace class TestableFileWriter : public WebFileWriterBase { public: explicit TestableFileWriter(blink::WebFileWriterClient* client) : WebFileWriterBase(mock_path_as_gurl(), client) { reset(); } void reset() { received_truncate_ = false; received_truncate_path_ = GURL(); received_truncate_offset_ = kNoOffset; received_write_ = false; received_write_path_ = GURL(); received_write_offset_ = kNoOffset; received_write_blob_uuid_ = std::string(); received_cancel_ = false; } bool received_truncate_; GURL received_truncate_path_; int64 received_truncate_offset_; bool received_write_; GURL received_write_path_; std::string received_write_blob_uuid_; int64 received_write_offset_; bool received_cancel_; protected: virtual void DoTruncate(const GURL& path, int64 offset) OVERRIDE { received_truncate_ = true; received_truncate_path_ = path; received_truncate_offset_ = offset; if (offset == kBasicFileTruncate_Offset) { DidSucceed(); } else if (offset == kErrorFileTruncate_Offset) { DidFail(base::File::FILE_ERROR_NOT_FOUND); } else if (offset == kCancelFileTruncate_Offset) { cancel(); DidSucceed(); // truncate completion DidSucceed(); // cancel completion } else if (offset == kCancelFailedTruncate_Offset) { cancel(); DidFail(base::File::FILE_ERROR_NOT_FOUND); // truncate completion DidSucceed(); // cancel completion } else { FAIL(); } } virtual void DoWrite( const GURL& path, const std::string& blob_uuid, int64 offset) OVERRIDE { received_write_ = true; received_write_path_ = path; received_write_offset_ = offset; received_write_blob_uuid_ = blob_uuid; if (offset == kBasicFileWrite_Offset) { DidWrite(1, true); } else if (offset == kErrorFileWrite_Offset) { DidFail(base::File::FILE_ERROR_NOT_FOUND); } else if (offset == kMultiFileWrite_Offset) { DidWrite(1, false); DidWrite(1, false); DidWrite(1, true); } else if (offset == kCancelFileWriteBeforeCompletion_Offset) { DidWrite(1, false); cancel(); DidWrite(1, false); DidWrite(1, false); DidFail(base::File::FILE_ERROR_FAILED); // write completion DidSucceed(); // cancel completion } else if (offset == kCancelFileWriteAfterCompletion_Offset) { DidWrite(1, false); cancel(); DidWrite(1, false); DidWrite(1, false); DidWrite(1, true); // write completion DidFail(base::File::FILE_ERROR_FAILED); // cancel completion } else { FAIL(); } } virtual void DoCancel() OVERRIDE { received_cancel_ = true; } }; class FileWriterTest : public testing::Test, public blink::WebFileWriterClient { public: FileWriterTest() { reset(); } blink::WebFileWriter* writer() { return testable_writer_.get(); } // WebFileWriterClient overrides virtual void didWrite(long long bytes, bool complete) { EXPECT_FALSE(received_did_write_complete_); ++received_did_write_count_; received_did_write_bytes_total_ += bytes; if (complete) received_did_write_complete_ = true; if (delete_in_client_callback_) testable_writer_.reset(NULL); } virtual void didTruncate() { EXPECT_FALSE(received_did_truncate_); received_did_truncate_ = true; if (delete_in_client_callback_) testable_writer_.reset(NULL); } virtual void didFail(blink::WebFileError error) { EXPECT_FALSE(received_did_fail_); received_did_fail_ = true; fail_error_received_ = error; if (delete_in_client_callback_) testable_writer_.reset(NULL); } protected: void reset() { testable_writer_.reset(new TestableFileWriter(this)); delete_in_client_callback_ = false; received_did_write_count_ = 0; received_did_write_bytes_total_ = 0; received_did_write_complete_ = false; received_did_truncate_ = false; received_did_fail_ = false; fail_error_received_ = static_cast<blink::WebFileError>(0); } scoped_ptr<TestableFileWriter> testable_writer_; bool delete_in_client_callback_; // Observed WebFileWriterClient artifacts. int received_did_write_count_; long long received_did_write_bytes_total_; bool received_did_write_complete_; bool received_did_truncate_; bool received_did_fail_; blink::WebFileError fail_error_received_; DISALLOW_COPY_AND_ASSIGN(FileWriterTest); }; TEST_F(FileWriterTest, BasicFileWrite) { // Call the webkit facing api. const std::string kBlobId("1234"); writer()->write(kBasicFileWrite_Offset, blink::WebString::fromUTF8(kBlobId)); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_write_); EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_gurl()); EXPECT_EQ(kBasicFileWrite_Offset, testable_writer_->received_write_offset_); EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); EXPECT_FALSE(testable_writer_->received_truncate_); EXPECT_FALSE(testable_writer_->received_cancel_); // Check that the client gets called correctly. EXPECT_EQ(1, received_did_write_count_); EXPECT_TRUE(received_did_write_complete_); EXPECT_EQ(1, received_did_write_bytes_total_); EXPECT_FALSE(received_did_truncate_); EXPECT_FALSE(received_did_fail_); } TEST_F(FileWriterTest, BasicFileTruncate) { // Call the webkit facing api. writer()->truncate(kBasicFileTruncate_Offset); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_truncate_); EXPECT_EQ(mock_path_as_gurl(), testable_writer_->received_truncate_path_); EXPECT_EQ(kBasicFileTruncate_Offset, testable_writer_->received_truncate_offset_); EXPECT_FALSE(testable_writer_->received_write_); EXPECT_FALSE(testable_writer_->received_cancel_); // Check that the client gets called correctly. EXPECT_TRUE(received_did_truncate_); EXPECT_EQ(0, received_did_write_count_); EXPECT_FALSE(received_did_fail_); } TEST_F(FileWriterTest, ErrorFileWrite) { // Call the webkit facing api. const std::string kBlobId("1234"); writer()->write(kErrorFileWrite_Offset, blink::WebString::fromUTF8(kBlobId)); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_write_); EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_gurl()); EXPECT_EQ(kErrorFileWrite_Offset, testable_writer_->received_write_offset_); EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); EXPECT_FALSE(testable_writer_->received_truncate_); EXPECT_FALSE(testable_writer_->received_cancel_); // Check that the client gets called correctly. EXPECT_TRUE(received_did_fail_); EXPECT_EQ(blink::WebFileErrorNotFound, fail_error_received_); EXPECT_EQ(0, received_did_write_count_); EXPECT_FALSE(received_did_truncate_); } TEST_F(FileWriterTest, ErrorFileTruncate) { // Call the webkit facing api. writer()->truncate(kErrorFileTruncate_Offset); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_truncate_); EXPECT_EQ(mock_path_as_gurl(), testable_writer_->received_truncate_path_); EXPECT_EQ(kErrorFileTruncate_Offset, testable_writer_->received_truncate_offset_); EXPECT_FALSE(testable_writer_->received_write_); EXPECT_FALSE(testable_writer_->received_cancel_); // Check that the client gets called correctly. EXPECT_TRUE(received_did_fail_); EXPECT_EQ(blink::WebFileErrorNotFound, fail_error_received_); EXPECT_FALSE(received_did_truncate_); EXPECT_EQ(0, received_did_write_count_); } TEST_F(FileWriterTest, MultiFileWrite) { // Call the webkit facing api. const std::string kBlobId("1234"); writer()->write(kMultiFileWrite_Offset, blink::WebString::fromUTF8(kBlobId)); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_write_); EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_gurl()); EXPECT_EQ(kMultiFileWrite_Offset, testable_writer_->received_write_offset_); EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); EXPECT_FALSE(testable_writer_->received_truncate_); EXPECT_FALSE(testable_writer_->received_cancel_); // Check that the client gets called correctly. EXPECT_EQ(3, received_did_write_count_); EXPECT_TRUE(received_did_write_complete_); EXPECT_EQ(3, received_did_write_bytes_total_); EXPECT_FALSE(received_did_truncate_); EXPECT_FALSE(received_did_fail_); } TEST_F(FileWriterTest, CancelFileWriteBeforeCompletion) { // Call the webkit facing api. const std::string kBlobId("1234"); writer()->write(kCancelFileWriteBeforeCompletion_Offset, blink::WebString::fromUTF8(kBlobId)); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_write_); EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_gurl()); EXPECT_EQ(kCancelFileWriteBeforeCompletion_Offset, testable_writer_->received_write_offset_); EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); EXPECT_TRUE(testable_writer_->received_cancel_); EXPECT_FALSE(testable_writer_->received_truncate_); // Check that the client gets called correctly. EXPECT_TRUE(received_did_fail_); EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_); EXPECT_EQ(1, received_did_write_count_); EXPECT_FALSE(received_did_write_complete_); EXPECT_EQ(1, received_did_write_bytes_total_); EXPECT_FALSE(received_did_truncate_); } TEST_F(FileWriterTest, CancelFileWriteAfterCompletion) { // Call the webkit facing api. const std::string kBlobId("1234"); writer()->write(kCancelFileWriteAfterCompletion_Offset, blink::WebString::fromUTF8(kBlobId)); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_write_); EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_gurl()); EXPECT_EQ(kCancelFileWriteAfterCompletion_Offset, testable_writer_->received_write_offset_); EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); EXPECT_TRUE(testable_writer_->received_cancel_); EXPECT_FALSE(testable_writer_->received_truncate_); // Check that the client gets called correctly. EXPECT_TRUE(received_did_fail_); EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_); EXPECT_EQ(1, received_did_write_count_); EXPECT_FALSE(received_did_write_complete_); EXPECT_EQ(1, received_did_write_bytes_total_); EXPECT_FALSE(received_did_truncate_); } TEST_F(FileWriterTest, CancelFileTruncate) { // Call the webkit facing api. writer()->truncate(kCancelFileTruncate_Offset); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_truncate_); EXPECT_EQ(mock_path_as_gurl(), testable_writer_->received_truncate_path_); EXPECT_EQ(kCancelFileTruncate_Offset, testable_writer_->received_truncate_offset_); EXPECT_TRUE(testable_writer_->received_cancel_); EXPECT_FALSE(testable_writer_->received_write_); // Check that the client gets called correctly. EXPECT_TRUE(received_did_fail_); EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_); EXPECT_FALSE(received_did_truncate_); EXPECT_EQ(0, received_did_write_count_); } TEST_F(FileWriterTest, CancelFailedTruncate) { // Call the webkit facing api. writer()->truncate(kCancelFailedTruncate_Offset); // Check that the derived class gets called correctly. EXPECT_TRUE(testable_writer_->received_truncate_); EXPECT_EQ(mock_path_as_gurl(), testable_writer_->received_truncate_path_); EXPECT_EQ(kCancelFailedTruncate_Offset, testable_writer_->received_truncate_offset_); EXPECT_TRUE(testable_writer_->received_cancel_); EXPECT_FALSE(testable_writer_->received_write_); // Check that the client gets called correctly. EXPECT_TRUE(received_did_fail_); EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_); EXPECT_FALSE(received_did_truncate_); EXPECT_EQ(0, received_did_write_count_); } TEST_F(FileWriterTest, DeleteInCompletionCallbacks) { const std::string kBlobId("1234"); delete_in_client_callback_ = true; writer()->write(kBasicFileWrite_Offset, blink::WebString::fromUTF8(kBlobId)); EXPECT_FALSE(testable_writer_.get()); reset(); delete_in_client_callback_ = true; writer()->truncate(kBasicFileTruncate_Offset); EXPECT_FALSE(testable_writer_.get()); reset(); delete_in_client_callback_ = true; writer()->write(kErrorFileWrite_Offset, blink::WebString::fromUTF8(kBlobId)); EXPECT_FALSE(testable_writer_.get()); reset(); delete_in_client_callback_ = true; writer()->truncate(kErrorFileTruncate_Offset); EXPECT_FALSE(testable_writer_.get()); // Not crashing counts as passing. } } // namespace content