Chromium Code Reviews| Index: sql/mojo/vfs_unittest.cc | 
| diff --git a/sql/mojo/vfs_unittest.cc b/sql/mojo/vfs_unittest.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..cbe0476e4f83029ffe071ce6bbd66b8f8ffba0c2 | 
| --- /dev/null | 
| +++ b/sql/mojo/vfs_unittest.cc | 
| @@ -0,0 +1,313 @@ | 
| +// Copyright 2015 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 "components/filesystem/public/interfaces/file_system.mojom.h" | 
| +#include "mojo/application/public/cpp/application_impl.h" | 
| +#include "mojo/application/public/cpp/application_test_base.h" | 
| +#include "mojo/util/capture_util.h" | 
| +#include "sql/mojo/enable_mojo_fs.h" | 
| +#include "testing/gtest/include/gtest/gtest.h" | 
| +#include "third_party/sqlite/sqlite3.h" | 
| + | 
| +namespace base { | 
| + | 
| +// This deleter lets us be safe with sqlite3 objects, which aren't really the | 
| +// structs, but slabs of new uint8_t[size]. | 
| +template <> | 
| +struct DefaultDeleter<sqlite3_file> { | 
| + inline void operator()(sqlite3_file* ptr) const { | 
| + // Why don't we call file->pMethods->xClose() here? Because it's not | 
| + // guaranteed to be valid. sqlite3_file "objects" can be in partially | 
| + // initialized states. | 
| + delete [] reinterpret_cast<uint8_t*>(ptr); | 
| + } | 
| +}; | 
| + | 
| +} // namespace base | 
| + | 
| +namespace sql { | 
| + | 
| +const char kFileName[] = "TestingDatabase.db"; | 
| + | 
| +class VFSTest : public mojo::test::ApplicationTestBase { | 
| + public: | 
| + VFSTest() {} | 
| + ~VFSTest() override {} | 
| + | 
| + sqlite3_vfs* vfs() { | 
| + return sqlite3_vfs_find(NULL); | 
| + } | 
| + | 
| + scoped_ptr<sqlite3_file> MakeFile() { | 
| + return scoped_ptr<sqlite3_file>(reinterpret_cast<sqlite3_file*>( | 
| + new uint8_t[vfs()->szOsFile])); | 
| + } | 
| + | 
| + void SetUp() override { | 
| + mojo::test::ApplicationTestBase::SetUp(); | 
| + | 
| + mojo::URLRequestPtr request(mojo::URLRequest::New()); | 
| + request->url = mojo::String::From("mojo:filesystem"); | 
| + application_impl()->ConnectToService(request.Pass(), &files_); | 
| + | 
| + filesystem::FileError error = filesystem::FILE_ERROR_FAILED; | 
| + filesystem::DirectoryPtr directory; | 
| + files_->OpenFileSystem("temp", GetProxy(&directory), mojo::Capture(&error)); | 
| + ASSERT_TRUE(files_.WaitForIncomingResponse()); | 
| + ASSERT_EQ(filesystem::FILE_ERROR_OK, error); | 
| + | 
| + vfs_.reset(new ScopedMojoFilesystemVFS(directory.Pass())); | 
| + } | 
| + | 
| + void TearDown() override { | 
| + vfs_.reset(); | 
| + mojo::test::ApplicationTestBase::TearDown(); | 
| + } | 
| + | 
| + private: | 
| + filesystem::FileSystemPtr files_; | 
| + scoped_ptr<ScopedMojoFilesystemVFS> vfs_; | 
| + | 
| + DISALLOW_COPY_AND_ASSIGN(VFSTest); | 
| +}; | 
| + | 
| +TEST_F(VFSTest, TestInstalled) { | 
| + EXPECT_EQ("mojo", vfs()->zName); | 
| +} | 
| + | 
| +TEST_F(VFSTest, ExclusiveOpen) { | 
| + // Opening a non-existent file exclusively should work. | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_CREATE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + // Opening it a second time exclusively shouldn't. | 
| + scoped_ptr<sqlite3_file> file2(MakeFile()); | 
| + rc = vfs()->xOpen(vfs(), kFileName, file2.get(), | 
| + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_CREATE, | 
| + &out_flags); | 
| + EXPECT_NE(SQLITE_OK, rc); | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| +} | 
| + | 
| +TEST_F(VFSTest, NonexclusiveOpen) { | 
| + // Opening a non-existent file exclusively should work. | 
| 
 
Scott Hess - ex-Googler
2015/06/17 19:32:58
s/exclusively//;
 
 | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| 
 
Scott Hess - ex-Googler
2015/06/17 19:32:58
Seems to be an excess space left of the |.  Also b
 
Elliot Glaysher
2015/06/17 21:59:35
Done.
 
 | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + // Opening it a second time exclusively shouldn't. | 
| 
 
Scott Hess - ex-Googler
2015/06/17 19:32:58
"second time should work."
 
Elliot Glaysher
2015/06/17 21:59:35
Done.
 
 | 
| + scoped_ptr<sqlite3_file> file2(MakeFile()); | 
| + rc = vfs()->xOpen(vfs(), kFileName, file2.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| + file->pMethods->xClose(file2.get()); | 
| +} | 
| + | 
| +TEST_F(VFSTest, DeleteOnClose) { | 
| + { | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen( | 
| + vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + file->pMethods->xClose(file.get()); | 
| + } | 
| + | 
| + // The file shouldn't exist now. | 
| + int result = 0; | 
| + vfs()->xAccess(vfs(), kFileName, SQLITE_ACCESS_EXISTS, &result); | 
| + EXPECT_FALSE(result); | 
| +} | 
| + | 
| +TEST_F(VFSTest, TestNonExistence) { | 
| + // We shouldn't have a file exist yet in a fresh directory. | 
| + int result = 0; | 
| + vfs()->xAccess(vfs(), kFileName, SQLITE_ACCESS_EXISTS, &result); | 
| + EXPECT_FALSE(result); | 
| +} | 
| + | 
| +TEST_F(VFSTest, TestExistence) { | 
| + { | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| + } | 
| + | 
| + int result = 0; | 
| + vfs()->xAccess(vfs(), kFileName, SQLITE_ACCESS_EXISTS, &result); | 
| + EXPECT_TRUE(result); | 
| +} | 
| + | 
| +TEST_F(VFSTest, TestDelete) { | 
| + { | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| + } | 
| + | 
| + int result = 0; | 
| + vfs()->xAccess(vfs(), kFileName, SQLITE_ACCESS_EXISTS, &result); | 
| + EXPECT_TRUE(result); | 
| + | 
| + vfs()->xDelete(vfs(), kFileName, 0); | 
| + | 
| + vfs()->xAccess(vfs(), kFileName, SQLITE_ACCESS_EXISTS, &result); | 
| + EXPECT_FALSE(result); | 
| +} | 
| + | 
| +TEST_F(VFSTest, TestWriteAndRead) { | 
| + const char kBuffer[] = "One Two Three Four Five Six Seven"; | 
| + const int kBufferSize = arraysize(kBuffer); | 
| + | 
| + { | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + for (int i = 0; i < 10; ++i) { | 
| + rc = file->pMethods->xWrite(file.get(), kBuffer, kBufferSize, | 
| + i * kBufferSize); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + } | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| + } | 
| + | 
| + // Expect that the size of the file is 10 * arraysize(kBuffer); | 
| + { | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + sqlite_int64 size; | 
| + rc = file->pMethods->xFileSize(file.get(), &size); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + EXPECT_EQ(10 * kBufferSize, size); | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| + } | 
| + | 
| + // We should be able to read things back. | 
| + { | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + char data_buffer[kBufferSize]; | 
| + for (int i = 0; i < 10; ++i) { | 
| + rc = file->pMethods->xRead(file.get(), data_buffer, kBufferSize, | 
| + i * kBufferSize); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + EXPECT_TRUE(strncmp(kBuffer, &data_buffer[0], kBufferSize) == 0); | 
| + } | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| + } | 
| +} | 
| + | 
| +TEST_F(VFSTest, PartialRead) { | 
| + const char kBuffer[] = "One Two Three Four Five Six Seven"; | 
| + const int kBufferSize = arraysize(kBuffer); | 
| + | 
| + // Write the data once. | 
| + { | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + rc = file->pMethods->xWrite(file.get(), kBuffer, kBufferSize, 0); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| + } | 
| + | 
| + // Now attempt to read kBufferSize + 5 from a file sized to kBufferSize. | 
| + { | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + char data_buffer[kBufferSize + 5]; | 
| 
 
Scott Hess - ex-Googler
2015/06/17 19:32:58
Suggest pre-filling the buffer with something that
 
Elliot Glaysher
2015/06/17 21:59:35
Done.
 
 | 
| + rc = file->pMethods->xRead(file.get(), data_buffer, kBufferSize + 5, 0); | 
| + EXPECT_EQ(SQLITE_IOERR_SHORT_READ, rc); | 
| + | 
| + const char kBufferWithFiveNulls[] = | 
| + "One Two Three Four Five Six Seven\0\0\0\0\0"; | 
| + const int kBufferWithFiveNullsSize = arraysize(kBuffer); | 
| 
 
Scott Hess - ex-Googler
2015/06/17 19:32:58
kBufferWithFiveNullsSize might make a good size fo
 
Elliot Glaysher
2015/06/17 21:59:35
Done.
 
 | 
| + EXPECT_TRUE(strncmp(kBufferWithFiveNulls, &data_buffer[0], | 
| + kBufferWithFiveNullsSize) == 0); | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| + } | 
| +} | 
| + | 
| +TEST_F(VFSTest, Truncate) { | 
| + const char kBuffer[] = "One Two Three Four Five Six Seven"; | 
| + const int kBufferSize = arraysize(kBuffer); | 
| + const int kCharsToThree = 13; | 
| + | 
| + scoped_ptr<sqlite3_file> file(MakeFile()); | 
| + int out_flags; | 
| + int rc = vfs()->xOpen(vfs(), kFileName, file.get(), | 
| + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, | 
| + &out_flags); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + rc = file->pMethods->xWrite(file.get(), kBuffer, kBufferSize, 0); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + sqlite_int64 size; | 
| + rc = file->pMethods->xFileSize(file.get(), &size); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + EXPECT_EQ(kBufferSize, size); | 
| + | 
| + rc = file->pMethods->xTruncate(file.get(), kCharsToThree); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + | 
| + rc = file->pMethods->xFileSize(file.get(), &size); | 
| + EXPECT_EQ(SQLITE_OK, rc); | 
| + EXPECT_EQ(kCharsToThree, size); | 
| + | 
| + file->pMethods->xClose(file.get()); | 
| +} | 
| + | 
| +} // namespace sql |