1// Copyright (c) 2011 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 "base/callback.h"
6#include "base/file_util.h"
7#include "base/message_loop.h"
8#include "base/path_service.h"
9#include "base/platform_file.h"
10#include "net/base/file_stream.h"
11#include "net/base/net_errors.h"
12#include "net/base/test_completion_callback.h"
13#include "testing/gtest/include/gtest/gtest.h"
14#include "testing/platform_test.h"
15
16namespace net {
17namespace {
18
19const char kTestData[] = "0123456789";
20const int kTestDataSize = arraysize(kTestData) - 1;
21
22class FileStreamTest : public PlatformTest {
23 public:
24  virtual void SetUp() {
25    PlatformTest::SetUp();
26
27    file_util::CreateTemporaryFile(&temp_file_path_);
28    file_util::WriteFile(temp_file_path_, kTestData, kTestDataSize);
29  }
30  virtual void TearDown() {
31    file_util::Delete(temp_file_path_, false);
32
33    PlatformTest::TearDown();
34  }
35  const FilePath temp_file_path() const { return temp_file_path_; }
36 private:
37  FilePath temp_file_path_;
38};
39
40TEST_F(FileStreamTest, BasicOpenClose) {
41  FileStream stream;
42  int rv = stream.Open(temp_file_path(),
43      base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
44  EXPECT_EQ(OK, rv);
45}
46
47// Test the use of FileStream with a file handle provided at construction.
48TEST_F(FileStreamTest, UseFileHandle) {
49  bool created = false;
50
51  // 1. Test reading with a file handle.
52  ASSERT_EQ(kTestDataSize,
53      file_util::WriteFile(temp_file_path(), kTestData, kTestDataSize));
54  int flags = base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ;
55  base::PlatformFile file = base::CreatePlatformFile(
56      temp_file_path(), flags, &created, NULL);
57
58  // Seek to the beginning of the file and read.
59  FileStream read_stream(file, flags);
60  ASSERT_EQ(0, read_stream.Seek(FROM_BEGIN, 0));
61  ASSERT_EQ(kTestDataSize, read_stream.Available());
62  // Read into buffer and compare.
63  char buffer[kTestDataSize];
64  ASSERT_EQ(kTestDataSize, read_stream.Read(buffer, kTestDataSize, NULL));
65  ASSERT_EQ(0, memcmp(kTestData, buffer, kTestDataSize));
66  read_stream.Close();
67
68  // 2. Test writing with a file handle.
69  file_util::Delete(temp_file_path(), false);
70  flags = base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE;
71  file = base::CreatePlatformFile(temp_file_path(), flags, &created, NULL);
72
73  FileStream write_stream(file, flags);
74  ASSERT_EQ(0, write_stream.Seek(FROM_BEGIN, 0));
75  ASSERT_EQ(kTestDataSize, write_stream.Write(kTestData, kTestDataSize, NULL));
76  write_stream.Close();
77
78  // Read into buffer and compare to make sure the handle worked fine.
79  ASSERT_EQ(kTestDataSize,
80      file_util::ReadFile(temp_file_path(), buffer, kTestDataSize));
81  ASSERT_EQ(0, memcmp(kTestData, buffer, kTestDataSize));
82}
83
84TEST_F(FileStreamTest, UseClosedStream) {
85  FileStream stream;
86
87  EXPECT_FALSE(stream.IsOpen());
88
89  // Try seeking...
90  int64 new_offset = stream.Seek(FROM_BEGIN, 5);
91  EXPECT_EQ(ERR_UNEXPECTED, new_offset);
92
93  // Try available...
94  int64 avail = stream.Available();
95  EXPECT_EQ(ERR_UNEXPECTED, avail);
96
97  // Try reading...
98  char buf[10];
99  int rv = stream.Read(buf, arraysize(buf), NULL);
100  EXPECT_EQ(ERR_UNEXPECTED, rv);
101}
102
103TEST_F(FileStreamTest, BasicRead) {
104  int64 file_size;
105  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
106  EXPECT_TRUE(ok);
107
108  FileStream stream;
109  int flags = base::PLATFORM_FILE_OPEN |
110              base::PLATFORM_FILE_READ;
111  int rv = stream.Open(temp_file_path(), flags);
112  EXPECT_EQ(OK, rv);
113
114  int64 total_bytes_avail = stream.Available();
115  EXPECT_EQ(file_size, total_bytes_avail);
116
117  int total_bytes_read = 0;
118
119  std::string data_read;
120  for (;;) {
121    char buf[4];
122    rv = stream.Read(buf, arraysize(buf), NULL);
123    EXPECT_LE(0, rv);
124    if (rv <= 0)
125      break;
126    total_bytes_read += rv;
127    data_read.append(buf, rv);
128  }
129  EXPECT_EQ(file_size, total_bytes_read);
130  EXPECT_EQ(kTestData, data_read);
131}
132
133TEST_F(FileStreamTest, AsyncRead) {
134  int64 file_size;
135  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
136  EXPECT_TRUE(ok);
137
138  FileStream stream;
139  int flags = base::PLATFORM_FILE_OPEN |
140              base::PLATFORM_FILE_READ |
141              base::PLATFORM_FILE_ASYNC;
142  int rv = stream.Open(temp_file_path(), flags);
143  EXPECT_EQ(OK, rv);
144
145  int64 total_bytes_avail = stream.Available();
146  EXPECT_EQ(file_size, total_bytes_avail);
147
148  TestCompletionCallback callback;
149
150  int total_bytes_read = 0;
151
152  std::string data_read;
153  for (;;) {
154    char buf[4];
155    rv = stream.Read(buf, arraysize(buf), &callback);
156    if (rv == ERR_IO_PENDING)
157      rv = callback.WaitForResult();
158    EXPECT_LE(0, rv);
159    if (rv <= 0)
160      break;
161    total_bytes_read += rv;
162    data_read.append(buf, rv);
163  }
164  EXPECT_EQ(file_size, total_bytes_read);
165  EXPECT_EQ(kTestData, data_read);
166}
167
168TEST_F(FileStreamTest, AsyncRead_EarlyClose) {
169  int64 file_size;
170  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
171  EXPECT_TRUE(ok);
172
173  FileStream stream;
174  int flags = base::PLATFORM_FILE_OPEN |
175              base::PLATFORM_FILE_READ |
176              base::PLATFORM_FILE_ASYNC;
177  int rv = stream.Open(temp_file_path(), flags);
178  EXPECT_EQ(OK, rv);
179
180  int64 total_bytes_avail = stream.Available();
181  EXPECT_EQ(file_size, total_bytes_avail);
182
183  TestCompletionCallback callback;
184
185  char buf[4];
186  rv = stream.Read(buf, arraysize(buf), &callback);
187  stream.Close();
188  if (rv < 0) {
189    EXPECT_EQ(ERR_IO_PENDING, rv);
190    // The callback should not be called if the request is cancelled.
191    MessageLoop::current()->RunAllPending();
192    EXPECT_FALSE(callback.have_result());
193  } else {
194    EXPECT_EQ(std::string(kTestData, rv), std::string(buf, rv));
195  }
196}
197
198TEST_F(FileStreamTest, BasicRead_FromOffset) {
199  int64 file_size;
200  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
201  EXPECT_TRUE(ok);
202
203  FileStream stream;
204  int flags = base::PLATFORM_FILE_OPEN |
205              base::PLATFORM_FILE_READ;
206  int rv = stream.Open(temp_file_path(), flags);
207  EXPECT_EQ(OK, rv);
208
209  const int64 kOffset = 3;
210  int64 new_offset = stream.Seek(FROM_BEGIN, kOffset);
211  EXPECT_EQ(kOffset, new_offset);
212
213  int64 total_bytes_avail = stream.Available();
214  EXPECT_EQ(file_size - kOffset, total_bytes_avail);
215
216  int64 total_bytes_read = 0;
217
218  std::string data_read;
219  for (;;) {
220    char buf[4];
221    rv = stream.Read(buf, arraysize(buf), NULL);
222    EXPECT_LE(0, rv);
223    if (rv <= 0)
224      break;
225    total_bytes_read += rv;
226    data_read.append(buf, rv);
227  }
228  EXPECT_EQ(file_size - kOffset, total_bytes_read);
229  EXPECT_TRUE(data_read == kTestData + kOffset);
230  EXPECT_EQ(kTestData + kOffset, data_read);
231}
232
233TEST_F(FileStreamTest, AsyncRead_FromOffset) {
234  int64 file_size;
235  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
236  EXPECT_TRUE(ok);
237
238  FileStream stream;
239  int flags = base::PLATFORM_FILE_OPEN |
240              base::PLATFORM_FILE_READ |
241              base::PLATFORM_FILE_ASYNC;
242  int rv = stream.Open(temp_file_path(), flags);
243  EXPECT_EQ(OK, rv);
244
245  const int64 kOffset = 3;
246  int64 new_offset = stream.Seek(FROM_BEGIN, kOffset);
247  EXPECT_EQ(kOffset, new_offset);
248
249  int64 total_bytes_avail = stream.Available();
250  EXPECT_EQ(file_size - kOffset, total_bytes_avail);
251
252  TestCompletionCallback callback;
253
254  int total_bytes_read = 0;
255
256  std::string data_read;
257  for (;;) {
258    char buf[4];
259    rv = stream.Read(buf, arraysize(buf), &callback);
260    if (rv == ERR_IO_PENDING)
261      rv = callback.WaitForResult();
262    EXPECT_LE(0, rv);
263    if (rv <= 0)
264      break;
265    total_bytes_read += rv;
266    data_read.append(buf, rv);
267  }
268  EXPECT_EQ(file_size - kOffset, total_bytes_read);
269  EXPECT_EQ(kTestData + kOffset, data_read);
270}
271
272TEST_F(FileStreamTest, SeekAround) {
273  FileStream stream;
274  int flags = base::PLATFORM_FILE_OPEN |
275              base::PLATFORM_FILE_READ;
276  int rv = stream.Open(temp_file_path(), flags);
277  EXPECT_EQ(OK, rv);
278
279  const int64 kOffset = 3;
280  int64 new_offset = stream.Seek(FROM_BEGIN, kOffset);
281  EXPECT_EQ(kOffset, new_offset);
282
283  new_offset = stream.Seek(FROM_CURRENT, kOffset);
284  EXPECT_EQ(2 * kOffset, new_offset);
285
286  new_offset = stream.Seek(FROM_CURRENT, -kOffset);
287  EXPECT_EQ(kOffset, new_offset);
288
289  const int kTestDataLen = arraysize(kTestData) - 1;
290
291  new_offset = stream.Seek(FROM_END, -kTestDataLen);
292  EXPECT_EQ(0, new_offset);
293}
294
295TEST_F(FileStreamTest, BasicWrite) {
296  FileStream stream;
297  int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
298              base::PLATFORM_FILE_WRITE;
299  int rv = stream.Open(temp_file_path(), flags);
300  EXPECT_EQ(OK, rv);
301
302  int64 file_size;
303  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
304  EXPECT_TRUE(ok);
305  EXPECT_EQ(0, file_size);
306
307  rv = stream.Write(kTestData, kTestDataSize, NULL);
308  EXPECT_EQ(kTestDataSize, rv);
309  stream.Close();
310
311  ok = file_util::GetFileSize(temp_file_path(), &file_size);
312  EXPECT_TRUE(ok);
313  EXPECT_EQ(kTestDataSize, file_size);
314}
315
316TEST_F(FileStreamTest, AsyncWrite) {
317  FileStream stream;
318  int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
319              base::PLATFORM_FILE_WRITE |
320              base::PLATFORM_FILE_ASYNC;
321  int rv = stream.Open(temp_file_path(), flags);
322  EXPECT_EQ(OK, rv);
323
324  int64 file_size;
325  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
326  EXPECT_TRUE(ok);
327  EXPECT_EQ(0, file_size);
328
329  TestCompletionCallback callback;
330  int total_bytes_written = 0;
331
332  while (total_bytes_written != kTestDataSize) {
333    rv = stream.Write(kTestData + total_bytes_written,
334                      kTestDataSize - total_bytes_written,
335                      &callback);
336    if (rv == ERR_IO_PENDING)
337      rv = callback.WaitForResult();
338    EXPECT_LT(0, rv);
339    if (rv <= 0)
340      break;
341    total_bytes_written += rv;
342  }
343  ok = file_util::GetFileSize(temp_file_path(), &file_size);
344  EXPECT_TRUE(ok);
345  EXPECT_EQ(file_size, total_bytes_written);
346}
347
348TEST_F(FileStreamTest, AsyncWrite_EarlyClose) {
349  FileStream stream;
350  int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
351              base::PLATFORM_FILE_WRITE |
352              base::PLATFORM_FILE_ASYNC;
353  int rv = stream.Open(temp_file_path(), flags);
354  EXPECT_EQ(OK, rv);
355
356  int64 file_size;
357  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
358  EXPECT_TRUE(ok);
359  EXPECT_EQ(0, file_size);
360
361  TestCompletionCallback callback;
362  int total_bytes_written = 0;
363
364  rv = stream.Write(kTestData + total_bytes_written,
365                    kTestDataSize - total_bytes_written,
366                    &callback);
367  stream.Close();
368  if (rv < 0) {
369    EXPECT_EQ(ERR_IO_PENDING, rv);
370    // The callback should not be called if the request is cancelled.
371    MessageLoop::current()->RunAllPending();
372    EXPECT_FALSE(callback.have_result());
373  } else {
374    ok = file_util::GetFileSize(temp_file_path(), &file_size);
375    EXPECT_TRUE(ok);
376    EXPECT_EQ(file_size, rv);
377  }
378}
379
380TEST_F(FileStreamTest, BasicWrite_FromOffset) {
381  FileStream stream;
382  int flags = base::PLATFORM_FILE_OPEN |
383              base::PLATFORM_FILE_WRITE;
384  int rv = stream.Open(temp_file_path(), flags);
385  EXPECT_EQ(OK, rv);
386
387  int64 file_size;
388  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
389  EXPECT_TRUE(ok);
390  EXPECT_EQ(kTestDataSize, file_size);
391
392  const int64 kOffset = 0;
393  int64 new_offset = stream.Seek(FROM_END, kOffset);
394  EXPECT_EQ(kTestDataSize, new_offset);
395
396  rv = stream.Write(kTestData, kTestDataSize, NULL);
397  EXPECT_EQ(kTestDataSize, rv);
398  stream.Close();
399
400  ok = file_util::GetFileSize(temp_file_path(), &file_size);
401  EXPECT_TRUE(ok);
402  EXPECT_EQ(kTestDataSize * 2, file_size);
403}
404
405TEST_F(FileStreamTest, AsyncWrite_FromOffset) {
406  int64 file_size;
407  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
408  EXPECT_TRUE(ok);
409
410  FileStream stream;
411  int flags = base::PLATFORM_FILE_OPEN |
412              base::PLATFORM_FILE_WRITE |
413              base::PLATFORM_FILE_ASYNC;
414  int rv = stream.Open(temp_file_path(), flags);
415  EXPECT_EQ(OK, rv);
416
417  const int64 kOffset = 0;
418  int64 new_offset = stream.Seek(FROM_END, kOffset);
419  EXPECT_EQ(kTestDataSize, new_offset);
420
421  TestCompletionCallback callback;
422  int total_bytes_written = 0;
423
424  while (total_bytes_written != kTestDataSize) {
425    rv = stream.Write(kTestData + total_bytes_written,
426                      kTestDataSize - total_bytes_written,
427                      &callback);
428    if (rv == ERR_IO_PENDING)
429      rv = callback.WaitForResult();
430    EXPECT_LT(0, rv);
431    if (rv <= 0)
432      break;
433    total_bytes_written += rv;
434  }
435  ok = file_util::GetFileSize(temp_file_path(), &file_size);
436  EXPECT_TRUE(ok);
437  EXPECT_EQ(file_size, kTestDataSize * 2);
438}
439
440TEST_F(FileStreamTest, BasicReadWrite) {
441  int64 file_size;
442  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
443  EXPECT_TRUE(ok);
444
445  FileStream stream;
446  int flags = base::PLATFORM_FILE_OPEN |
447              base::PLATFORM_FILE_READ |
448              base::PLATFORM_FILE_WRITE;
449  int rv = stream.Open(temp_file_path(), flags);
450  EXPECT_EQ(OK, rv);
451
452  int64 total_bytes_avail = stream.Available();
453  EXPECT_EQ(file_size, total_bytes_avail);
454
455  int total_bytes_read = 0;
456
457  std::string data_read;
458  for (;;) {
459    char buf[4];
460    rv = stream.Read(buf, arraysize(buf), NULL);
461    EXPECT_LE(0, rv);
462    if (rv <= 0)
463      break;
464    total_bytes_read += rv;
465    data_read.append(buf, rv);
466  }
467  EXPECT_EQ(file_size, total_bytes_read);
468  EXPECT_TRUE(data_read == kTestData);
469
470  rv = stream.Write(kTestData, kTestDataSize, NULL);
471  EXPECT_EQ(kTestDataSize, rv);
472  stream.Close();
473
474  ok = file_util::GetFileSize(temp_file_path(), &file_size);
475  EXPECT_TRUE(ok);
476  EXPECT_EQ(kTestDataSize * 2, file_size);
477}
478
479TEST_F(FileStreamTest, BasicWriteRead) {
480  int64 file_size;
481  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
482  EXPECT_TRUE(ok);
483
484  FileStream stream;
485  int flags = base::PLATFORM_FILE_OPEN |
486              base::PLATFORM_FILE_READ |
487              base::PLATFORM_FILE_WRITE;
488  int rv = stream.Open(temp_file_path(), flags);
489  EXPECT_EQ(OK, rv);
490
491  int64 total_bytes_avail = stream.Available();
492  EXPECT_EQ(file_size, total_bytes_avail);
493
494  int64 offset = stream.Seek(FROM_END, 0);
495  EXPECT_EQ(offset, file_size);
496
497  rv = stream.Write(kTestData, kTestDataSize, NULL);
498  EXPECT_EQ(kTestDataSize, rv);
499
500  offset = stream.Seek(FROM_BEGIN, 0);
501  EXPECT_EQ(0, offset);
502
503  int64 total_bytes_read = 0;
504
505  std::string data_read;
506  for (;;) {
507    char buf[4];
508    rv = stream.Read(buf, arraysize(buf), NULL);
509    EXPECT_LE(0, rv);
510    if (rv <= 0)
511      break;
512    total_bytes_read += rv;
513    data_read.append(buf, rv);
514  }
515  stream.Close();
516
517  ok = file_util::GetFileSize(temp_file_path(), &file_size);
518  EXPECT_TRUE(ok);
519  EXPECT_EQ(kTestDataSize * 2, file_size);
520  EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
521
522  const std::string kExpectedFileData =
523      std::string(kTestData) + std::string(kTestData);
524  EXPECT_EQ(kExpectedFileData, data_read);
525}
526
527TEST_F(FileStreamTest, BasicAsyncReadWrite) {
528  int64 file_size;
529  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
530  EXPECT_TRUE(ok);
531
532  FileStream stream;
533  int flags = base::PLATFORM_FILE_OPEN |
534              base::PLATFORM_FILE_READ |
535              base::PLATFORM_FILE_WRITE |
536              base::PLATFORM_FILE_ASYNC;
537  int rv = stream.Open(temp_file_path(), flags);
538  EXPECT_EQ(OK, rv);
539
540  int64 total_bytes_avail = stream.Available();
541  EXPECT_EQ(file_size, total_bytes_avail);
542
543  TestCompletionCallback callback;
544  int64 total_bytes_read = 0;
545
546  std::string data_read;
547  for (;;) {
548    char buf[4];
549    rv = stream.Read(buf, arraysize(buf), &callback);
550    if (rv == ERR_IO_PENDING)
551      rv = callback.WaitForResult();
552    EXPECT_LE(0, rv);
553    if (rv <= 0)
554      break;
555    total_bytes_read += rv;
556    data_read.append(buf, rv);
557  }
558  EXPECT_EQ(file_size, total_bytes_read);
559  EXPECT_TRUE(data_read == kTestData);
560
561  int total_bytes_written = 0;
562
563  while (total_bytes_written != kTestDataSize) {
564    rv = stream.Write(kTestData + total_bytes_written,
565                      kTestDataSize - total_bytes_written,
566                      &callback);
567    if (rv == ERR_IO_PENDING)
568      rv = callback.WaitForResult();
569    EXPECT_LT(0, rv);
570    if (rv <= 0)
571      break;
572    total_bytes_written += rv;
573  }
574
575  stream.Close();
576
577  ok = file_util::GetFileSize(temp_file_path(), &file_size);
578  EXPECT_TRUE(ok);
579  EXPECT_EQ(kTestDataSize * 2, file_size);
580}
581
582TEST_F(FileStreamTest, BasicAsyncWriteRead) {
583  int64 file_size;
584  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
585  EXPECT_TRUE(ok);
586
587  FileStream stream;
588  int flags = base::PLATFORM_FILE_OPEN |
589              base::PLATFORM_FILE_READ |
590              base::PLATFORM_FILE_WRITE |
591              base::PLATFORM_FILE_ASYNC;
592  int rv = stream.Open(temp_file_path(), flags);
593  EXPECT_EQ(OK, rv);
594
595  int64 total_bytes_avail = stream.Available();
596  EXPECT_EQ(file_size, total_bytes_avail);
597
598  int64 offset = stream.Seek(FROM_END, 0);
599  EXPECT_EQ(offset, file_size);
600
601  TestCompletionCallback callback;
602  int total_bytes_written = 0;
603
604  while (total_bytes_written != kTestDataSize) {
605    rv = stream.Write(kTestData + total_bytes_written,
606                      kTestDataSize - total_bytes_written,
607                      &callback);
608    if (rv == ERR_IO_PENDING)
609      rv = callback.WaitForResult();
610    EXPECT_LT(0, rv);
611    if (rv <= 0)
612      break;
613    total_bytes_written += rv;
614  }
615
616  EXPECT_EQ(kTestDataSize, total_bytes_written);
617
618  offset = stream.Seek(FROM_BEGIN, 0);
619  EXPECT_EQ(0, offset);
620
621  int total_bytes_read = 0;
622
623  std::string data_read;
624  for (;;) {
625    char buf[4];
626    rv = stream.Read(buf, arraysize(buf), &callback);
627    if (rv == ERR_IO_PENDING)
628      rv = callback.WaitForResult();
629    EXPECT_LE(0, rv);
630    if (rv <= 0)
631      break;
632    total_bytes_read += rv;
633    data_read.append(buf, rv);
634  }
635  stream.Close();
636
637  ok = file_util::GetFileSize(temp_file_path(), &file_size);
638  EXPECT_TRUE(ok);
639  EXPECT_EQ(kTestDataSize * 2, file_size);
640
641  EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
642  const std::string kExpectedFileData =
643      std::string(kTestData) + std::string(kTestData);
644  EXPECT_EQ(kExpectedFileData, data_read);
645}
646
647class TestWriteReadCompletionCallback : public Callback1<int>::Type {
648 public:
649  explicit TestWriteReadCompletionCallback(
650      FileStream* stream,
651      int* total_bytes_written,
652      int* total_bytes_read,
653      std::string* data_read)
654      : result_(0),
655        have_result_(false),
656        waiting_for_result_(false),
657        stream_(stream),
658        total_bytes_written_(total_bytes_written),
659        total_bytes_read_(total_bytes_read),
660        data_read_(data_read) {}
661
662  int WaitForResult() {
663    DCHECK(!waiting_for_result_);
664    while (!have_result_) {
665      waiting_for_result_ = true;
666      MessageLoop::current()->Run();
667      waiting_for_result_ = false;
668    }
669    have_result_ = false;  // auto-reset for next callback
670    return result_;
671  }
672
673 private:
674  virtual void RunWithParams(const Tuple1<int>& params) {
675    DCHECK_LT(0, params.a);
676    *total_bytes_written_ += params.a;
677
678    int rv;
679
680    if (*total_bytes_written_ != kTestDataSize) {
681      // Recurse to finish writing all data.
682      int total_bytes_written = 0, total_bytes_read = 0;
683      std::string data_read;
684      TestWriteReadCompletionCallback callback(
685          stream_, &total_bytes_written, &total_bytes_read, &data_read);
686      rv = stream_->Write(kTestData + *total_bytes_written_,
687                          kTestDataSize - *total_bytes_written_,
688                          &callback);
689      DCHECK_EQ(ERR_IO_PENDING, rv);
690      rv = callback.WaitForResult();
691      *total_bytes_written_ += total_bytes_written;
692      *total_bytes_read_ += total_bytes_read;
693      *data_read_ += data_read;
694    } else {  // We're done writing all data.  Start reading the data.
695      stream_->Seek(FROM_BEGIN, 0);
696
697      TestCompletionCallback callback;
698      for (;;) {
699        char buf[4];
700        rv = stream_->Read(buf, arraysize(buf), &callback);
701        if (rv == ERR_IO_PENDING) {
702          bool old_state = MessageLoop::current()->NestableTasksAllowed();
703          MessageLoop::current()->SetNestableTasksAllowed(true);
704          rv = callback.WaitForResult();
705          MessageLoop::current()->SetNestableTasksAllowed(old_state);
706        }
707        EXPECT_LE(0, rv);
708        if (rv <= 0)
709          break;
710        *total_bytes_read_ += rv;
711        data_read_->append(buf, rv);
712      }
713    }
714
715    result_ = *total_bytes_written_;
716    have_result_ = true;
717    if (waiting_for_result_)
718      MessageLoop::current()->Quit();
719  }
720
721  int result_;
722  bool have_result_;
723  bool waiting_for_result_;
724  FileStream* stream_;
725  int* total_bytes_written_;
726  int* total_bytes_read_;
727  std::string* data_read_;
728
729  DISALLOW_COPY_AND_ASSIGN(TestWriteReadCompletionCallback);
730};
731
732TEST_F(FileStreamTest, AsyncWriteRead) {
733  int64 file_size;
734  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
735  EXPECT_TRUE(ok);
736
737  FileStream stream;
738  int flags = base::PLATFORM_FILE_OPEN |
739              base::PLATFORM_FILE_READ |
740              base::PLATFORM_FILE_WRITE |
741              base::PLATFORM_FILE_ASYNC;
742  int rv = stream.Open(temp_file_path(), flags);
743  EXPECT_EQ(OK, rv);
744
745  int64 total_bytes_avail = stream.Available();
746  EXPECT_EQ(file_size, total_bytes_avail);
747
748  int64 offset = stream.Seek(FROM_END, 0);
749  EXPECT_EQ(offset, file_size);
750
751  int total_bytes_written = 0;
752  int total_bytes_read = 0;
753  std::string data_read;
754  TestWriteReadCompletionCallback callback(&stream, &total_bytes_written,
755                                           &total_bytes_read, &data_read);
756
757  rv = stream.Write(kTestData + total_bytes_written,
758                    kTestDataSize - static_cast<int>(total_bytes_written),
759                    &callback);
760  if (rv == ERR_IO_PENDING)
761    rv = callback.WaitForResult();
762  EXPECT_LT(0, rv);
763  EXPECT_EQ(kTestDataSize, total_bytes_written);
764
765  stream.Close();
766
767  ok = file_util::GetFileSize(temp_file_path(), &file_size);
768  EXPECT_TRUE(ok);
769  EXPECT_EQ(kTestDataSize * 2, file_size);
770
771  EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
772  const std::string kExpectedFileData =
773      std::string(kTestData) + std::string(kTestData);
774  EXPECT_EQ(kExpectedFileData, data_read);
775}
776
777class TestWriteCloseCompletionCallback : public Callback1<int>::Type {
778 public:
779  explicit TestWriteCloseCompletionCallback(FileStream* stream,
780                                            int* total_bytes_written)
781      : result_(0),
782        have_result_(false),
783        waiting_for_result_(false),
784        stream_(stream),
785        total_bytes_written_(total_bytes_written) {}
786
787  int WaitForResult() {
788    DCHECK(!waiting_for_result_);
789    while (!have_result_) {
790      waiting_for_result_ = true;
791      MessageLoop::current()->Run();
792      waiting_for_result_ = false;
793    }
794    have_result_ = false;  // auto-reset for next callback
795    return result_;
796  }
797
798 private:
799  virtual void RunWithParams(const Tuple1<int>& params) {
800    DCHECK_LT(0, params.a);
801    *total_bytes_written_ += params.a;
802
803    int rv;
804
805    if (*total_bytes_written_ != kTestDataSize) {
806      // Recurse to finish writing all data.
807      int total_bytes_written = 0;
808      TestWriteCloseCompletionCallback callback(stream_, &total_bytes_written);
809      rv = stream_->Write(kTestData + *total_bytes_written_,
810                          kTestDataSize - *total_bytes_written_,
811                          &callback);
812      DCHECK_EQ(ERR_IO_PENDING, rv);
813      rv = callback.WaitForResult();
814      *total_bytes_written_ += total_bytes_written;
815    } else {  // We're done writing all data.  Close the file.
816      stream_->Close();
817    }
818
819    result_ = *total_bytes_written_;
820    have_result_ = true;
821    if (waiting_for_result_)
822      MessageLoop::current()->Quit();
823  }
824
825  int result_;
826  bool have_result_;
827  bool waiting_for_result_;
828  FileStream* stream_;
829  int* total_bytes_written_;
830
831  DISALLOW_COPY_AND_ASSIGN(TestWriteCloseCompletionCallback);
832};
833
834TEST_F(FileStreamTest, AsyncWriteClose) {
835  int64 file_size;
836  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
837  EXPECT_TRUE(ok);
838
839  FileStream stream;
840  int flags = base::PLATFORM_FILE_OPEN |
841              base::PLATFORM_FILE_READ |
842              base::PLATFORM_FILE_WRITE |
843              base::PLATFORM_FILE_ASYNC;
844  int rv = stream.Open(temp_file_path(), flags);
845  EXPECT_EQ(OK, rv);
846
847  int64 total_bytes_avail = stream.Available();
848  EXPECT_EQ(file_size, total_bytes_avail);
849
850  int64 offset = stream.Seek(FROM_END, 0);
851  EXPECT_EQ(offset, file_size);
852
853  int total_bytes_written = 0;
854  TestWriteCloseCompletionCallback callback(&stream, &total_bytes_written);
855
856  rv = stream.Write(kTestData, kTestDataSize, &callback);
857  if (rv == ERR_IO_PENDING)
858    total_bytes_written = callback.WaitForResult();
859  EXPECT_LT(0, total_bytes_written);
860  EXPECT_EQ(kTestDataSize, total_bytes_written);
861
862  ok = file_util::GetFileSize(temp_file_path(), &file_size);
863  EXPECT_TRUE(ok);
864  EXPECT_EQ(kTestDataSize * 2, file_size);
865}
866
867// Tests truncating a file.
868TEST_F(FileStreamTest, Truncate) {
869  int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
870
871  FileStream write_stream;
872  ASSERT_EQ(OK, write_stream.Open(temp_file_path(), flags));
873
874  // Write some data to the file.
875  const char test_data[] = "0123456789";
876  write_stream.Write(test_data, arraysize(test_data), NULL);
877
878  // Truncate the file.
879  ASSERT_EQ(4, write_stream.Truncate(4));
880
881  // Write again.
882  write_stream.Write(test_data, 4, NULL);
883
884  // Close the stream.
885  write_stream.Close();
886
887  // Read in the contents and make sure we get back what we expected.
888  std::string read_contents;
889  EXPECT_TRUE(file_util::ReadFileToString(temp_file_path(), &read_contents));
890
891  EXPECT_EQ("01230123", read_contents);
892}
893
894}  // namespace
895}  // namespace net
896