diff options
Diffstat (limited to 'runtime/base/unix_file/mapped_file_test.cc')
-rw-r--r-- | runtime/base/unix_file/mapped_file_test.cc | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/runtime/base/unix_file/mapped_file_test.cc b/runtime/base/unix_file/mapped_file_test.cc new file mode 100644 index 0000000000..a3b097dcae --- /dev/null +++ b/runtime/base/unix_file/mapped_file_test.cc @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "base/unix_file/mapped_file.h" +#include "base/logging.h" +#include "base/unix_file/fd_file.h" +#include "base/unix_file/random_access_file_test.h" +#include "base/unix_file/random_access_file_utils.h" +#include "base/unix_file/string_file.h" +#include "gtest/gtest.h" + +namespace unix_file { + +class MappedFileTest : public RandomAccessFileTest { + protected: + MappedFileTest() : kContent("some content") { + } + + void SetUp() { + art::CommonTest::SetEnvironmentVariables(android_data_); + + good_path_ = GetTmpPath("some-file.txt"); + int fd = TEMP_FAILURE_RETRY(open(good_path_.c_str(), O_CREAT|O_RDWR, 0666)); + FdFile dst(fd); + + StringFile src; + src.Assign(kContent); + + ASSERT_TRUE(CopyFile(src, &dst)); + } + + virtual RandomAccessFile* MakeTestFile() { + TEMP_FAILURE_RETRY(truncate(good_path_.c_str(), 0)); + MappedFile* f = new MappedFile; + CHECK(f->Open(good_path_, MappedFile::kReadWriteMode)); + return f; + } + + const std::string kContent; + std::string good_path_; +}; + +TEST_F(MappedFileTest, OkayToNotUse) { + MappedFile file; + EXPECT_EQ(-1, file.Fd()); + EXPECT_FALSE(file.IsOpened()); + EXPECT_FALSE(file.IsMapped()); +} + +TEST_F(MappedFileTest, OpenClose) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_GE(file.Fd(), 0); + EXPECT_TRUE(file.IsOpened()); + EXPECT_EQ(kContent.size(), file.size()); + EXPECT_EQ(0, file.Close()); + EXPECT_EQ(-1, file.Fd()); + EXPECT_FALSE(file.IsOpened()); +} + +TEST_F(MappedFileTest, OpenFdClose) { + FILE* f = tmpfile(); + ASSERT_TRUE(f != NULL); + MappedFile file(fileno(f)); + EXPECT_GE(file.Fd(), 0); + EXPECT_TRUE(file.IsOpened()); + EXPECT_EQ(0, file.Close()); +} + +TEST_F(MappedFileTest, CanUseAfterMapReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_FALSE(file.IsMapped()); + EXPECT_TRUE(file.MapReadOnly()); + EXPECT_TRUE(file.IsMapped()); + EXPECT_EQ(kContent.size(), file.size()); + ASSERT_TRUE(file.data()); + EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), file.size())); + EXPECT_EQ(0, file.Flush()); +} + +TEST_F(MappedFileTest, CanUseAfterMapReadWrite) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + EXPECT_FALSE(file.IsMapped()); + EXPECT_TRUE(file.MapReadWrite(1)); + EXPECT_TRUE(file.IsMapped()); + EXPECT_EQ(1, file.size()); + ASSERT_TRUE(file.data()); + EXPECT_EQ(kContent[0], *file.data()); + EXPECT_EQ(0, file.Flush()); +} + +TEST_F(MappedFileTest, CanWriteNewData) { + const std::string new_path(GetTmpPath("new-file.txt")); + ASSERT_EQ(-1, unlink(new_path.c_str())); + ASSERT_EQ(ENOENT, errno); + + MappedFile file; + ASSERT_TRUE(file.Open(new_path, MappedFile::kReadWriteMode)); + EXPECT_TRUE(file.MapReadWrite(kContent.size())); + EXPECT_TRUE(file.IsMapped()); + EXPECT_EQ(kContent.size(), file.size()); + ASSERT_TRUE(file.data()); + memcpy(file.data(), kContent.c_str(), kContent.size()); + EXPECT_EQ(0, file.Close()); + EXPECT_FALSE(file.IsMapped()); + + FdFile new_file(TEMP_FAILURE_RETRY(open(new_path.c_str(), O_RDONLY))); + StringFile buffer; + ASSERT_TRUE(CopyFile(new_file, &buffer)); + EXPECT_EQ(kContent, buffer.ToStringPiece()); + EXPECT_EQ(0, unlink(new_path.c_str())); +} + +TEST_F(MappedFileTest, FileMustExist) { + const std::string bad_path(GetTmpPath("does-not-exist.txt")); + MappedFile file; + EXPECT_FALSE(file.Open(bad_path, MappedFile::kReadOnlyMode)); + EXPECT_EQ(-1, file.Fd()); +} + +TEST_F(MappedFileTest, FileMustBeWritable) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_FALSE(file.MapReadWrite(10)); +} + +TEST_F(MappedFileTest, RemappingAllowedUntilSuccess) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_FALSE(file.MapReadWrite(10)); + EXPECT_FALSE(file.MapReadWrite(10)); +} + +TEST_F(MappedFileTest, ResizeMappedFile) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(10)); + EXPECT_EQ(10, file.GetLength()); + EXPECT_TRUE(file.Unmap()); + EXPECT_TRUE(file.MapReadWrite(20)); + EXPECT_EQ(20, file.GetLength()); + EXPECT_EQ(0, file.Flush()); + EXPECT_TRUE(file.Unmap()); + EXPECT_EQ(0, file.Flush()); + EXPECT_EQ(0, file.SetLength(5)); + EXPECT_TRUE(file.MapReadOnly()); + EXPECT_EQ(5, file.GetLength()); +} + +TEST_F(MappedFileTest, ReadNotMapped) { + TestRead(); +} + +TEST_F(MappedFileTest, SetLengthNotMapped) { + TestSetLength(); +} + +TEST_F(MappedFileTest, WriteNotMapped) { + TestWrite(); +} + +TEST_F(MappedFileTest, ReadMappedReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + ASSERT_TRUE(file.MapReadOnly()); + TestReadContent(kContent, &file); +} + +TEST_F(MappedFileTest, ReadMappedReadWrite) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(kContent.size())); + TestReadContent(kContent, &file); +} + +TEST_F(MappedFileTest, WriteMappedReadWrite) { + TEMP_FAILURE_RETRY(unlink(good_path_.c_str())); + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(kContent.size())); + + // Can't write to a negative offset. + EXPECT_EQ(-EINVAL, file.Write(kContent.c_str(), 0, -123)); + + // A zero-length write is a no-op. + EXPECT_EQ(0, file.Write(kContent.c_str(), 0, 0)); + // But the file size is as given when mapped. + EXPECT_EQ(kContent.size(), file.GetLength()); + + // Data written past the end are discarded. + EXPECT_EQ(kContent.size() - 1, + file.Write(kContent.c_str(), kContent.size(), 1)); + EXPECT_EQ(0, memcmp(kContent.c_str(), file.data() + 1, kContent.size() - 1)); + + // Data can be overwritten. + EXPECT_EQ(kContent.size(), file.Write(kContent.c_str(), kContent.size(), 0)); + EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), kContent.size())); +} + +#if 0 // death tests don't work on android yet + +class MappedFileDeathTest : public MappedFileTest {}; + +TEST_F(MappedFileDeathTest, MustMapBeforeUse) { + MappedFile file; + EXPECT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_DEATH(file.data(), "mapped_"); +} + +TEST_F(MappedFileDeathTest, RemappingNotAllowedReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + ASSERT_TRUE(file.MapReadOnly()); + EXPECT_DEATH(file.MapReadOnly(), "mapped_"); +} + +TEST_F(MappedFileDeathTest, RemappingNotAllowedReadWrite) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(10)); + EXPECT_DEATH(file.MapReadWrite(10), "mapped_"); +} + +TEST_F(MappedFileDeathTest, SetLengthMappedReadWrite) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(10)); + EXPECT_EQ(10, file.GetLength()); + EXPECT_DEATH(file.SetLength(0), ".*"); +} + +TEST_F(MappedFileDeathTest, SetLengthMappedReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + ASSERT_TRUE(file.MapReadOnly()); + EXPECT_EQ(kContent.size(), file.GetLength()); + EXPECT_DEATH(file.SetLength(0), ".*"); +} + +TEST_F(MappedFileDeathTest, WriteMappedReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + ASSERT_TRUE(file.MapReadOnly()); + char buf[10]; + EXPECT_DEATH(file.Write(buf, 0, 0), ".*"); +} + +#endif + +} // namespace unix_file |