diff options
Diffstat (limited to 'sql/mojo/vfs_unittest.cc')
-rw-r--r-- | sql/mojo/vfs_unittest.cc | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/sql/mojo/vfs_unittest.cc b/sql/mojo/vfs_unittest.cc new file mode 100644 index 0000000..8ca7c5c --- /dev/null +++ b/sql/mojo/vfs_unittest.cc @@ -0,0 +1,317 @@ +// 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/mojo_vfs.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 should work. + 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); + + // Opening it a second time should work. + 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]; + memset(data_buffer, '8', 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); + + const char kBufferWithFiveNulls[] = + "One Two Three Four Five Six Seven\0\0\0\0\0"; + const int kBufferWithFiveNullsSize = arraysize(kBufferWithFiveNulls); + + char data_buffer[kBufferWithFiveNullsSize]; + memset(data_buffer, '8', kBufferWithFiveNullsSize); + rc = file->pMethods->xRead(file.get(), data_buffer, + kBufferWithFiveNullsSize, 0); + EXPECT_EQ(SQLITE_IOERR_SHORT_READ, rc); + + 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 |