1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "base/unix_file/fd_file.h" 18#include "base/unix_file/random_access_file_test.h" 19#include "common_runtime_test.h" // For ScratchFile 20#include "gtest/gtest.h" 21 22namespace unix_file { 23 24class FdFileTest : public RandomAccessFileTest { 25 protected: 26 virtual RandomAccessFile* MakeTestFile() { 27 return new FdFile(fileno(tmpfile()), false); 28 } 29}; 30 31TEST_F(FdFileTest, Read) { 32 TestRead(); 33} 34 35TEST_F(FdFileTest, SetLength) { 36 TestSetLength(); 37} 38 39TEST_F(FdFileTest, Write) { 40 TestWrite(); 41} 42 43TEST_F(FdFileTest, UnopenedFile) { 44 FdFile file; 45 EXPECT_EQ(-1, file.Fd()); 46 EXPECT_FALSE(file.IsOpened()); 47 EXPECT_TRUE(file.GetPath().empty()); 48} 49 50TEST_F(FdFileTest, OpenClose) { 51 std::string good_path(GetTmpPath("some-file.txt")); 52 FdFile file(good_path, O_CREAT | O_WRONLY, true); 53 ASSERT_TRUE(file.IsOpened()); 54 EXPECT_GE(file.Fd(), 0); 55 EXPECT_TRUE(file.IsOpened()); 56 EXPECT_FALSE(file.ReadOnlyMode()); 57 EXPECT_EQ(0, file.Flush()); 58 EXPECT_EQ(0, file.Close()); 59 EXPECT_EQ(-1, file.Fd()); 60 EXPECT_FALSE(file.IsOpened()); 61 FdFile file2(good_path, O_RDONLY, true); 62 EXPECT_TRUE(file2.IsOpened()); 63 EXPECT_TRUE(file2.ReadOnlyMode()); 64 EXPECT_GE(file2.Fd(), 0); 65 66 ASSERT_EQ(file2.Close(), 0); 67 ASSERT_EQ(unlink(good_path.c_str()), 0); 68} 69 70TEST_F(FdFileTest, ReadFullyEmptyFile) { 71 // New scratch file, zero-length. 72 art::ScratchFile tmp; 73 FdFile file(tmp.GetFilename(), O_RDONLY, false); 74 ASSERT_TRUE(file.IsOpened()); 75 EXPECT_TRUE(file.ReadOnlyMode()); 76 EXPECT_GE(file.Fd(), 0); 77 uint8_t buffer[16]; 78 EXPECT_FALSE(file.ReadFully(&buffer, 4)); 79} 80 81template <size_t Size> 82static void NullTerminateCharArray(char (&array)[Size]) { 83 array[Size - 1] = '\0'; 84} 85 86TEST_F(FdFileTest, ReadFullyWithOffset) { 87 // New scratch file, zero-length. 88 art::ScratchFile tmp; 89 FdFile file(tmp.GetFilename(), O_RDWR, false); 90 ASSERT_TRUE(file.IsOpened()); 91 EXPECT_GE(file.Fd(), 0); 92 EXPECT_FALSE(file.ReadOnlyMode()); 93 94 char ignore_prefix[20] = {'a', }; 95 NullTerminateCharArray(ignore_prefix); 96 char read_suffix[10] = {'b', }; 97 NullTerminateCharArray(read_suffix); 98 99 off_t offset = 0; 100 // Write scratch data to file that we can read back into. 101 EXPECT_TRUE(file.Write(ignore_prefix, sizeof(ignore_prefix), offset)); 102 offset += sizeof(ignore_prefix); 103 EXPECT_TRUE(file.Write(read_suffix, sizeof(read_suffix), offset)); 104 105 ASSERT_EQ(file.Flush(), 0); 106 107 // Reading at an offset should only produce 'bbbb...', since we ignore the 'aaa...' prefix. 108 char buffer[sizeof(read_suffix)]; 109 EXPECT_TRUE(file.PreadFully(buffer, sizeof(read_suffix), offset)); 110 EXPECT_STREQ(&read_suffix[0], &buffer[0]); 111 112 ASSERT_EQ(file.Close(), 0); 113} 114 115TEST_F(FdFileTest, ReadWriteFullyWithOffset) { 116 // New scratch file, zero-length. 117 art::ScratchFile tmp; 118 FdFile file(tmp.GetFilename(), O_RDWR, false); 119 ASSERT_GE(file.Fd(), 0); 120 EXPECT_TRUE(file.IsOpened()); 121 EXPECT_FALSE(file.ReadOnlyMode()); 122 123 const char* test_string = "This is a test string"; 124 size_t length = strlen(test_string) + 1; 125 const size_t offset = 12; 126 std::unique_ptr<char[]> offset_read_string(new char[length]); 127 std::unique_ptr<char[]> read_string(new char[length]); 128 129 // Write scratch data to file that we can read back into. 130 EXPECT_TRUE(file.PwriteFully(test_string, length, offset)); 131 ASSERT_EQ(file.Flush(), 0); 132 133 // Test reading both the offsets. 134 EXPECT_TRUE(file.PreadFully(&offset_read_string[0], length, offset)); 135 EXPECT_STREQ(test_string, &offset_read_string[0]); 136 137 EXPECT_TRUE(file.PreadFully(&read_string[0], length, 0u)); 138 EXPECT_NE(memcmp(&read_string[0], test_string, length), 0); 139 140 ASSERT_EQ(file.Close(), 0); 141} 142 143TEST_F(FdFileTest, Copy) { 144 art::ScratchFile src_tmp; 145 FdFile src(src_tmp.GetFilename(), O_RDWR, false); 146 ASSERT_GE(src.Fd(), 0); 147 ASSERT_TRUE(src.IsOpened()); 148 149 char src_data[] = "Some test data."; 150 ASSERT_TRUE(src.WriteFully(src_data, sizeof(src_data))); // Including the zero terminator. 151 ASSERT_EQ(0, src.Flush()); 152 ASSERT_EQ(static_cast<int64_t>(sizeof(src_data)), src.GetLength()); 153 154 art::ScratchFile dest_tmp; 155 FdFile dest(src_tmp.GetFilename(), O_RDWR, false); 156 ASSERT_GE(dest.Fd(), 0); 157 ASSERT_TRUE(dest.IsOpened()); 158 159 ASSERT_TRUE(dest.Copy(&src, 0, sizeof(src_data))); 160 ASSERT_EQ(0, dest.Flush()); 161 ASSERT_EQ(static_cast<int64_t>(sizeof(src_data)), dest.GetLength()); 162 163 char check_data[sizeof(src_data)]; 164 ASSERT_TRUE(dest.PreadFully(check_data, sizeof(src_data), 0u)); 165 CHECK_EQ(0, memcmp(check_data, src_data, sizeof(src_data))); 166 167 ASSERT_EQ(0, dest.Close()); 168 ASSERT_EQ(0, src.Close()); 169} 170 171TEST_F(FdFileTest, MoveConstructor) { 172 // New scratch file, zero-length. 173 art::ScratchFile tmp; 174 FdFile file(tmp.GetFilename(), O_RDWR, false); 175 ASSERT_TRUE(file.IsOpened()); 176 EXPECT_GE(file.Fd(), 0); 177 178 int old_fd = file.Fd(); 179 180 FdFile file2(std::move(file)); 181 EXPECT_FALSE(file.IsOpened()); 182 EXPECT_TRUE(file2.IsOpened()); 183 EXPECT_EQ(old_fd, file2.Fd()); 184 185 ASSERT_EQ(file2.Flush(), 0); 186 ASSERT_EQ(file2.Close(), 0); 187} 188 189TEST_F(FdFileTest, EraseWithPathUnlinks) { 190 // New scratch file, zero-length. 191 art::ScratchFile tmp; 192 std::string filename = tmp.GetFilename(); 193 tmp.Close(); // This is required because of the unlink race between the scratch file and the 194 // FdFile, which leads to close-guard breakage. 195 FdFile file(filename, O_RDWR, false); 196 ASSERT_TRUE(file.IsOpened()); 197 EXPECT_GE(file.Fd(), 0); 198 uint8_t buffer[16] = { 0 }; 199 EXPECT_TRUE(file.WriteFully(&buffer, sizeof(buffer))); 200 EXPECT_EQ(file.Flush(), 0); 201 202 EXPECT_TRUE(file.Erase(true)); 203 204 EXPECT_FALSE(file.IsOpened()); 205 206 EXPECT_FALSE(art::OS::FileExists(filename.c_str())) << filename; 207} 208 209} // namespace unix_file 210