1 //===- llvm/unittest/Support/FileOutputBuffer.cpp - unit tests ------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/Support/FileOutputBuffer.h"
11 #include "llvm/Support/Errc.h"
12 #include "llvm/Support/ErrorHandling.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/MemoryBuffer.h"
15 #include "llvm/Support/Path.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include "gtest/gtest.h"
20 using namespace llvm::sys
;
22 #define ASSERT_NO_ERROR(x) \
23 if (std::error_code ASSERT_NO_ERROR_ec = x) { \
24 SmallString<128> MessageStorage; \
25 raw_svector_ostream Message(MessageStorage); \
26 Message << #x ": did not return errc::success.\n" \
27 << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
28 << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
29 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
34 TEST(FileOutputBuffer
, Test
) {
35 // Create unique temporary directory for these tests
36 SmallString
<128> TestDirectory
;
39 fs::createUniqueDirectory("FileOutputBuffer-test", TestDirectory
));
42 // TEST 1: Verify commit case.
43 SmallString
<128> File1(TestDirectory
);
44 File1
.append("/file1");
46 Expected
<std::unique_ptr
<FileOutputBuffer
>> BufferOrErr
=
47 FileOutputBuffer::create(File1
, 8192);
48 ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr
.takeError()));
49 std::unique_ptr
<FileOutputBuffer
> &Buffer
= *BufferOrErr
;
50 // Start buffer with special header.
51 memcpy(Buffer
->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20);
52 // Write to end of buffer to verify it is writable.
53 memcpy(Buffer
->getBufferEnd() - 20, "AABBCCDDEEFFGGHHIIJJ", 20);
55 ASSERT_NO_ERROR(errorToErrorCode(Buffer
->commit()));
58 // Verify file is correct size.
60 ASSERT_NO_ERROR(fs::file_size(Twine(File1
), File1Size
));
61 ASSERT_EQ(File1Size
, 8192ULL);
62 ASSERT_NO_ERROR(fs::remove(File1
.str()));
64 // TEST 2: Verify abort case.
65 SmallString
<128> File2(TestDirectory
);
66 File2
.append("/file2");
68 Expected
<std::unique_ptr
<FileOutputBuffer
>> Buffer2OrErr
=
69 FileOutputBuffer::create(File2
, 8192);
70 ASSERT_NO_ERROR(errorToErrorCode(Buffer2OrErr
.takeError()));
71 std::unique_ptr
<FileOutputBuffer
> &Buffer2
= *Buffer2OrErr
;
72 // Fill buffer with special header.
73 memcpy(Buffer2
->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20);
74 // Do *not* commit buffer.
76 // Verify file does not exist (because buffer not committed).
77 ASSERT_EQ(fs::access(Twine(File2
), fs::AccessMode::Exist
),
78 errc::no_such_file_or_directory
);
79 ASSERT_NO_ERROR(fs::remove(File2
.str()));
81 // TEST 3: Verify sizing down case.
82 SmallString
<128> File3(TestDirectory
);
83 File3
.append("/file3");
85 Expected
<std::unique_ptr
<FileOutputBuffer
>> BufferOrErr
=
86 FileOutputBuffer::create(File3
, 8192000);
87 ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr
.takeError()));
88 std::unique_ptr
<FileOutputBuffer
> &Buffer
= *BufferOrErr
;
89 // Start buffer with special header.
90 memcpy(Buffer
->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20);
91 // Write to end of buffer to verify it is writable.
92 memcpy(Buffer
->getBufferEnd() - 20, "AABBCCDDEEFFGGHHIIJJ", 20);
93 ASSERT_NO_ERROR(errorToErrorCode(Buffer
->commit()));
96 // Verify file is correct size.
98 ASSERT_NO_ERROR(fs::file_size(Twine(File3
), File3Size
));
99 ASSERT_EQ(File3Size
, 8192000ULL);
100 ASSERT_NO_ERROR(fs::remove(File3
.str()));
102 // TEST 4: Verify file can be made executable.
103 SmallString
<128> File4(TestDirectory
);
104 File4
.append("/file4");
106 Expected
<std::unique_ptr
<FileOutputBuffer
>> BufferOrErr
=
107 FileOutputBuffer::create(File4
, 8192, FileOutputBuffer::F_executable
);
108 ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr
.takeError()));
109 std::unique_ptr
<FileOutputBuffer
> &Buffer
= *BufferOrErr
;
110 // Start buffer with special header.
111 memcpy(Buffer
->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20);
113 ASSERT_NO_ERROR(errorToErrorCode(Buffer
->commit()));
115 // Verify file exists and is executable.
116 fs::file_status Status
;
117 ASSERT_NO_ERROR(fs::status(Twine(File4
), Status
));
118 bool IsExecutable
= (Status
.permissions() & fs::owner_exe
);
119 EXPECT_TRUE(IsExecutable
);
120 ASSERT_NO_ERROR(fs::remove(File4
.str()));
123 ASSERT_NO_ERROR(fs::remove(TestDirectory
.str()));
126 TEST(FileOutputBuffer
, TestModify
) {
127 // Create unique temporary directory for these tests
128 SmallString
<128> TestDirectory
;
131 fs::createUniqueDirectory("FileOutputBuffer-modify", TestDirectory
));
134 SmallString
<128> File1(TestDirectory
);
135 File1
.append("/file");
136 // First write some data.
138 Expected
<std::unique_ptr
<FileOutputBuffer
>> BufferOrErr
=
139 FileOutputBuffer::create(File1
, 10);
140 ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr
.takeError()));
141 std::unique_ptr
<FileOutputBuffer
> &Buffer
= *BufferOrErr
;
142 memcpy(Buffer
->getBufferStart(), "AAAAAAAAAA", 10);
143 ASSERT_NO_ERROR(errorToErrorCode(Buffer
->commit()));
146 // Then re-open the file for modify and change only some bytes.
148 Expected
<std::unique_ptr
<FileOutputBuffer
>> BufferOrErr
=
149 FileOutputBuffer::create(File1
, size_t(-1), FileOutputBuffer::F_modify
);
150 ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr
.takeError()));
151 std::unique_ptr
<FileOutputBuffer
> &Buffer
= *BufferOrErr
;
152 ASSERT_EQ(10U, Buffer
->getBufferSize());
153 uint8_t *Data
= Buffer
->getBufferStart();
156 ASSERT_NO_ERROR(errorToErrorCode(Buffer
->commit()));
159 // Finally, re-open the file for read and verify that it has the modified
162 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufferOrErr
= MemoryBuffer::getFile(File1
);
163 ASSERT_NO_ERROR(BufferOrErr
.getError());
164 std::unique_ptr
<MemoryBuffer
> Buffer
= std::move(*BufferOrErr
);
165 ASSERT_EQ(10U, Buffer
->getBufferSize());
166 EXPECT_EQ(StringRef("XAAAAAAAAX"), Buffer
->getBuffer());
170 ASSERT_NO_ERROR(fs::remove(File1
));
171 ASSERT_NO_ERROR(fs::remove(TestDirectory
));
174 } // anonymous namespace