1 // Copyright 2013 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 #include "content/child/fileapi/webfilewriter_base.h" 6 7 #include "base/logging.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 #include "third_party/WebKit/public/platform/WebFileError.h" 13 #include "third_party/WebKit/public/platform/WebFileWriterClient.h" 14 #include "third_party/WebKit/public/platform/WebURL.h" 15 #include "url/gurl.h" 16 17 namespace content { 18 19 namespace { 20 21 // We use particular offsets to trigger particular behaviors 22 // in the TestableFileWriter. 23 const int kNoOffset = -1; 24 const int kBasicFileTruncate_Offset = 1; 25 const int kErrorFileTruncate_Offset = 2; 26 const int kCancelFileTruncate_Offset = 3; 27 const int kCancelFailedTruncate_Offset = 4; 28 const int kBasicFileWrite_Offset = 1; 29 const int kErrorFileWrite_Offset = 2; 30 const int kMultiFileWrite_Offset = 3; 31 const int kCancelFileWriteBeforeCompletion_Offset = 4; 32 const int kCancelFileWriteAfterCompletion_Offset = 5; 33 34 GURL mock_path_as_gurl() { 35 return GURL("MockPath"); 36 } 37 38 } // namespace 39 40 class TestableFileWriter : public WebFileWriterBase { 41 public: 42 explicit TestableFileWriter(blink::WebFileWriterClient* client) 43 : WebFileWriterBase(mock_path_as_gurl(), client) { 44 reset(); 45 } 46 47 void reset() { 48 received_truncate_ = false; 49 received_truncate_path_ = GURL(); 50 received_truncate_offset_ = kNoOffset; 51 received_write_ = false; 52 received_write_path_ = GURL(); 53 received_write_offset_ = kNoOffset; 54 received_write_blob_uuid_ = std::string(); 55 received_cancel_ = false; 56 } 57 58 bool received_truncate_; 59 GURL received_truncate_path_; 60 int64 received_truncate_offset_; 61 bool received_write_; 62 GURL received_write_path_; 63 std::string received_write_blob_uuid_; 64 int64 received_write_offset_; 65 bool received_cancel_; 66 67 protected: 68 virtual void DoTruncate(const GURL& path, int64 offset) OVERRIDE { 69 received_truncate_ = true; 70 received_truncate_path_ = path; 71 received_truncate_offset_ = offset; 72 73 if (offset == kBasicFileTruncate_Offset) { 74 DidSucceed(); 75 } else if (offset == kErrorFileTruncate_Offset) { 76 DidFail(base::PLATFORM_FILE_ERROR_NOT_FOUND); 77 } else if (offset == kCancelFileTruncate_Offset) { 78 cancel(); 79 DidSucceed(); // truncate completion 80 DidSucceed(); // cancel completion 81 } else if (offset == kCancelFailedTruncate_Offset) { 82 cancel(); 83 DidFail(base::PLATFORM_FILE_ERROR_NOT_FOUND); // truncate completion 84 DidSucceed(); // cancel completion 85 } else { 86 FAIL(); 87 } 88 } 89 90 virtual void DoWrite( 91 const GURL& path, const std::string& blob_uuid, 92 int64 offset) OVERRIDE { 93 received_write_ = true; 94 received_write_path_ = path; 95 received_write_offset_ = offset; 96 received_write_blob_uuid_ = blob_uuid; 97 98 if (offset == kBasicFileWrite_Offset) { 99 DidWrite(1, true); 100 } else if (offset == kErrorFileWrite_Offset) { 101 DidFail(base::PLATFORM_FILE_ERROR_NOT_FOUND); 102 } else if (offset == kMultiFileWrite_Offset) { 103 DidWrite(1, false); 104 DidWrite(1, false); 105 DidWrite(1, true); 106 } else if (offset == kCancelFileWriteBeforeCompletion_Offset) { 107 DidWrite(1, false); 108 cancel(); 109 DidWrite(1, false); 110 DidWrite(1, false); 111 DidFail(base::PLATFORM_FILE_ERROR_FAILED); // write completion 112 DidSucceed(); // cancel completion 113 } else if (offset == kCancelFileWriteAfterCompletion_Offset) { 114 DidWrite(1, false); 115 cancel(); 116 DidWrite(1, false); 117 DidWrite(1, false); 118 DidWrite(1, true); // write completion 119 DidFail(base::PLATFORM_FILE_ERROR_FAILED); // cancel completion 120 } else { 121 FAIL(); 122 } 123 } 124 125 virtual void DoCancel() OVERRIDE { 126 received_cancel_ = true; 127 } 128 }; 129 130 class FileWriterTest : public testing::Test, 131 public blink::WebFileWriterClient { 132 public: 133 FileWriterTest() { 134 reset(); 135 } 136 137 blink::WebFileWriter* writer() { 138 return testable_writer_.get(); 139 } 140 141 // WebFileWriterClient overrides 142 virtual void didWrite(long long bytes, bool complete) { 143 EXPECT_FALSE(received_did_write_complete_); 144 ++received_did_write_count_; 145 received_did_write_bytes_total_ += bytes; 146 if (complete) 147 received_did_write_complete_ = true; 148 149 if (delete_in_client_callback_) 150 testable_writer_.reset(NULL); 151 } 152 153 virtual void didTruncate() { 154 EXPECT_FALSE(received_did_truncate_); 155 received_did_truncate_ = true; 156 if (delete_in_client_callback_) 157 testable_writer_.reset(NULL); 158 } 159 160 virtual void didFail(blink::WebFileError error) { 161 EXPECT_FALSE(received_did_fail_); 162 received_did_fail_ = true; 163 fail_error_received_ = error; 164 if (delete_in_client_callback_) 165 testable_writer_.reset(NULL); 166 } 167 168 protected: 169 void reset() { 170 testable_writer_.reset(new TestableFileWriter(this)); 171 delete_in_client_callback_ = false; 172 received_did_write_count_ = 0; 173 received_did_write_bytes_total_ = 0; 174 received_did_write_complete_ = false; 175 received_did_truncate_ = false; 176 received_did_fail_ = false; 177 fail_error_received_ = static_cast<blink::WebFileError>(0); 178 } 179 180 scoped_ptr<TestableFileWriter> testable_writer_; 181 bool delete_in_client_callback_; 182 183 // Observed WebFileWriterClient artifacts. 184 int received_did_write_count_; 185 long long received_did_write_bytes_total_; 186 bool received_did_write_complete_; 187 bool received_did_truncate_; 188 bool received_did_fail_; 189 blink::WebFileError fail_error_received_; 190 191 DISALLOW_COPY_AND_ASSIGN(FileWriterTest); 192 }; 193 194 TEST_F(FileWriterTest, BasicFileWrite) { 195 // Call the webkit facing api. 196 const std::string kBlobId("1234"); 197 writer()->write(kBasicFileWrite_Offset, 198 blink::WebString::fromUTF8(kBlobId)); 199 200 // Check that the derived class gets called correctly. 201 EXPECT_TRUE(testable_writer_->received_write_); 202 EXPECT_EQ(testable_writer_->received_write_path_, 203 mock_path_as_gurl()); 204 EXPECT_EQ(kBasicFileWrite_Offset, 205 testable_writer_->received_write_offset_); 206 EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); 207 EXPECT_FALSE(testable_writer_->received_truncate_); 208 EXPECT_FALSE(testable_writer_->received_cancel_); 209 210 // Check that the client gets called correctly. 211 EXPECT_EQ(1, received_did_write_count_); 212 EXPECT_TRUE(received_did_write_complete_); 213 EXPECT_EQ(1, received_did_write_bytes_total_); 214 EXPECT_FALSE(received_did_truncate_); 215 EXPECT_FALSE(received_did_fail_); 216 } 217 218 TEST_F(FileWriterTest, BasicFileTruncate) { 219 // Call the webkit facing api. 220 writer()->truncate(kBasicFileTruncate_Offset); 221 222 // Check that the derived class gets called correctly. 223 EXPECT_TRUE(testable_writer_->received_truncate_); 224 EXPECT_EQ(mock_path_as_gurl(), 225 testable_writer_->received_truncate_path_); 226 EXPECT_EQ(kBasicFileTruncate_Offset, 227 testable_writer_->received_truncate_offset_); 228 EXPECT_FALSE(testable_writer_->received_write_); 229 EXPECT_FALSE(testable_writer_->received_cancel_); 230 231 // Check that the client gets called correctly. 232 EXPECT_TRUE(received_did_truncate_); 233 EXPECT_EQ(0, received_did_write_count_); 234 EXPECT_FALSE(received_did_fail_); 235 } 236 237 TEST_F(FileWriterTest, ErrorFileWrite) { 238 // Call the webkit facing api. 239 const std::string kBlobId("1234"); 240 writer()->write(kErrorFileWrite_Offset, 241 blink::WebString::fromUTF8(kBlobId)); 242 243 // Check that the derived class gets called correctly. 244 EXPECT_TRUE(testable_writer_->received_write_); 245 EXPECT_EQ(testable_writer_->received_write_path_, 246 mock_path_as_gurl()); 247 EXPECT_EQ(kErrorFileWrite_Offset, 248 testable_writer_->received_write_offset_); 249 EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); 250 EXPECT_FALSE(testable_writer_->received_truncate_); 251 EXPECT_FALSE(testable_writer_->received_cancel_); 252 253 // Check that the client gets called correctly. 254 EXPECT_TRUE(received_did_fail_); 255 EXPECT_EQ(blink::WebFileErrorNotFound, fail_error_received_); 256 EXPECT_EQ(0, received_did_write_count_); 257 EXPECT_FALSE(received_did_truncate_); 258 } 259 260 TEST_F(FileWriterTest, ErrorFileTruncate) { 261 // Call the webkit facing api. 262 writer()->truncate(kErrorFileTruncate_Offset); 263 264 // Check that the derived class gets called correctly. 265 EXPECT_TRUE(testable_writer_->received_truncate_); 266 EXPECT_EQ(mock_path_as_gurl(), 267 testable_writer_->received_truncate_path_); 268 EXPECT_EQ(kErrorFileTruncate_Offset, 269 testable_writer_->received_truncate_offset_); 270 EXPECT_FALSE(testable_writer_->received_write_); 271 EXPECT_FALSE(testable_writer_->received_cancel_); 272 273 // Check that the client gets called correctly. 274 EXPECT_TRUE(received_did_fail_); 275 EXPECT_EQ(blink::WebFileErrorNotFound, fail_error_received_); 276 EXPECT_FALSE(received_did_truncate_); 277 EXPECT_EQ(0, received_did_write_count_); 278 } 279 280 TEST_F(FileWriterTest, MultiFileWrite) { 281 // Call the webkit facing api. 282 const std::string kBlobId("1234"); 283 writer()->write(kMultiFileWrite_Offset, 284 blink::WebString::fromUTF8(kBlobId)); 285 286 // Check that the derived class gets called correctly. 287 EXPECT_TRUE(testable_writer_->received_write_); 288 EXPECT_EQ(testable_writer_->received_write_path_, 289 mock_path_as_gurl()); 290 EXPECT_EQ(kMultiFileWrite_Offset, 291 testable_writer_->received_write_offset_); 292 EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); 293 EXPECT_FALSE(testable_writer_->received_truncate_); 294 EXPECT_FALSE(testable_writer_->received_cancel_); 295 296 // Check that the client gets called correctly. 297 EXPECT_EQ(3, received_did_write_count_); 298 EXPECT_TRUE(received_did_write_complete_); 299 EXPECT_EQ(3, received_did_write_bytes_total_); 300 EXPECT_FALSE(received_did_truncate_); 301 EXPECT_FALSE(received_did_fail_); 302 } 303 304 TEST_F(FileWriterTest, CancelFileWriteBeforeCompletion) { 305 // Call the webkit facing api. 306 const std::string kBlobId("1234"); 307 writer()->write(kCancelFileWriteBeforeCompletion_Offset, 308 blink::WebString::fromUTF8(kBlobId)); 309 310 // Check that the derived class gets called correctly. 311 EXPECT_TRUE(testable_writer_->received_write_); 312 EXPECT_EQ(testable_writer_->received_write_path_, 313 mock_path_as_gurl()); 314 EXPECT_EQ(kCancelFileWriteBeforeCompletion_Offset, 315 testable_writer_->received_write_offset_); 316 EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); 317 EXPECT_TRUE(testable_writer_->received_cancel_); 318 EXPECT_FALSE(testable_writer_->received_truncate_); 319 320 // Check that the client gets called correctly. 321 EXPECT_TRUE(received_did_fail_); 322 EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_); 323 EXPECT_EQ(1, received_did_write_count_); 324 EXPECT_FALSE(received_did_write_complete_); 325 EXPECT_EQ(1, received_did_write_bytes_total_); 326 EXPECT_FALSE(received_did_truncate_); 327 } 328 329 TEST_F(FileWriterTest, CancelFileWriteAfterCompletion) { 330 // Call the webkit facing api. 331 const std::string kBlobId("1234"); 332 writer()->write(kCancelFileWriteAfterCompletion_Offset, 333 blink::WebString::fromUTF8(kBlobId)); 334 335 // Check that the derived class gets called correctly. 336 EXPECT_TRUE(testable_writer_->received_write_); 337 EXPECT_EQ(testable_writer_->received_write_path_, 338 mock_path_as_gurl()); 339 EXPECT_EQ(kCancelFileWriteAfterCompletion_Offset, 340 testable_writer_->received_write_offset_); 341 EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); 342 EXPECT_TRUE(testable_writer_->received_cancel_); 343 EXPECT_FALSE(testable_writer_->received_truncate_); 344 345 // Check that the client gets called correctly. 346 EXPECT_TRUE(received_did_fail_); 347 EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_); 348 EXPECT_EQ(1, received_did_write_count_); 349 EXPECT_FALSE(received_did_write_complete_); 350 EXPECT_EQ(1, received_did_write_bytes_total_); 351 EXPECT_FALSE(received_did_truncate_); 352 } 353 354 TEST_F(FileWriterTest, CancelFileTruncate) { 355 // Call the webkit facing api. 356 writer()->truncate(kCancelFileTruncate_Offset); 357 358 // Check that the derived class gets called correctly. 359 EXPECT_TRUE(testable_writer_->received_truncate_); 360 EXPECT_EQ(mock_path_as_gurl(), 361 testable_writer_->received_truncate_path_); 362 EXPECT_EQ(kCancelFileTruncate_Offset, 363 testable_writer_->received_truncate_offset_); 364 EXPECT_TRUE(testable_writer_->received_cancel_); 365 EXPECT_FALSE(testable_writer_->received_write_); 366 367 // Check that the client gets called correctly. 368 EXPECT_TRUE(received_did_fail_); 369 EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_); 370 EXPECT_FALSE(received_did_truncate_); 371 EXPECT_EQ(0, received_did_write_count_); 372 } 373 374 TEST_F(FileWriterTest, CancelFailedTruncate) { 375 // Call the webkit facing api. 376 writer()->truncate(kCancelFailedTruncate_Offset); 377 378 // Check that the derived class gets called correctly. 379 EXPECT_TRUE(testable_writer_->received_truncate_); 380 EXPECT_EQ(mock_path_as_gurl(), 381 testable_writer_->received_truncate_path_); 382 EXPECT_EQ(kCancelFailedTruncate_Offset, 383 testable_writer_->received_truncate_offset_); 384 EXPECT_TRUE(testable_writer_->received_cancel_); 385 EXPECT_FALSE(testable_writer_->received_write_); 386 387 // Check that the client gets called correctly. 388 EXPECT_TRUE(received_did_fail_); 389 EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_); 390 EXPECT_FALSE(received_did_truncate_); 391 EXPECT_EQ(0, received_did_write_count_); 392 } 393 394 TEST_F(FileWriterTest, DeleteInCompletionCallbacks) { 395 const std::string kBlobId("1234"); 396 delete_in_client_callback_ = true; 397 writer()->write(kBasicFileWrite_Offset, 398 blink::WebString::fromUTF8(kBlobId)); 399 EXPECT_FALSE(testable_writer_.get()); 400 401 reset(); 402 delete_in_client_callback_ = true; 403 writer()->truncate(kBasicFileTruncate_Offset); 404 EXPECT_FALSE(testable_writer_.get()); 405 406 reset(); 407 delete_in_client_callback_ = true; 408 writer()->write(kErrorFileWrite_Offset, 409 blink::WebString::fromUTF8(kBlobId)); 410 EXPECT_FALSE(testable_writer_.get()); 411 412 reset(); 413 delete_in_client_callback_ = true; 414 writer()->truncate(kErrorFileTruncate_Offset); 415 EXPECT_FALSE(testable_writer_.get()); 416 417 // Not crashing counts as passing. 418 } 419 420 } // namespace content 421