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 |