2121// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2222// OTHER DEALINGS IN THE SOFTWARE.
2323
24+ #include < cassert>
2425#include < cstdio>
2526#include < filesystem>
2627#include < fstream>
3334
3435namespace McBopomofo {
3536
37+ class TempFile {
38+ public:
39+ TempFile (const char * initData, size_t length) {
40+ std::filesystem::path p = std::filesystem::temp_directory_path () /
41+ " org.openvanilla.mcbopomofo.XXXXXX" ;
42+ path_ = p.native ();
43+
44+ int fd = mkstemp (path_.data ());
45+ assert (fd != -1 );
46+
47+ ssize_t written = write (fd, initData, length);
48+ assert (static_cast <size_t >(written) == length);
49+ (void )written;
50+
51+ close (fd);
52+ }
53+
54+ ~TempFile () {
55+ std::error_code ec;
56+ bool result = std::filesystem::remove (path_, ec);
57+ assert (result);
58+ (void )result;
59+ }
60+
61+ const char * path () const { return path_.c_str (); }
62+
63+ protected:
64+ std::string path_;
65+ };
66+
67+ class TempDir {
68+ public:
69+ TempDir () {
70+ std::filesystem::path p = std::filesystem::temp_directory_path () /
71+ " org.openvanilla.mcbopomofo.XXXXXX" ;
72+ path_ = p.native ();
73+ char * result = mkdtemp (path_.data ());
74+ assert (result != nullptr );
75+ fprintf (stderr, " TEMPDIR: %s\n " , result);
76+ }
77+
78+ ~TempDir () {
79+ std::error_code ec;
80+ bool result = std::filesystem::remove (path_, ec);
81+ assert (result);
82+ (void )result;
83+ }
84+
85+ const char * path () const { return path_.c_str (); }
86+
87+ protected:
88+ std::string path_;
89+ };
90+
3691TEST (MemoryMappedFileTest, UnopenedInstance) {
3792 MemoryMappedFile mf;
93+ EXPECT_FALSE (mf.isOpen ());
3894 EXPECT_EQ (mf.length (), 0 );
3995 EXPECT_EQ (mf.data (), nullptr );
4096}
4197
4298TEST (MemoryMappedFileTest, BasicFunctionalities) {
43- std::random_device rd;
44- std::default_random_engine re (rd ());
45- std::uniform_int_distribution<unsigned int > suffix_gen (0 );
46-
47- std::string prefix (" org.openvanilla.mcbopomofo.memorymappedfiletest-" );
48- std::filesystem::path tmp_file_path;
49-
50- constexpr int kMaxRetry = 10 ;
51- for (int i = 0 ; i < kMaxRetry ; ++i) {
52- std::string filename = prefix + std::to_string (suffix_gen (re));
53- std::filesystem::path p = std::filesystem::temp_directory_path () / filename;
54- if (!std::filesystem::exists (p)) {
55- tmp_file_path = p;
56- break ;
57- }
58- }
59- ASSERT_FALSE (tmp_file_path.empty ()) << " Must form a temp filename" ;
60-
6199 constexpr size_t kBufSize = 4 * 1024 * 1024 ;
62100 uint8_t * buf = new uint8_t [kBufSize ];
63101
102+ std::random_device rd;
103+ std::default_random_engine re (rd ());
104+
64105 std::uniform_int_distribution<unsigned int > randchar (0 , 255 );
65106 for (size_t i = 0 ; i < kBufSize ; ++i) {
66107 buf[i] = static_cast <uint8_t >(randchar (re) & 0xff );
67108 }
68109
69- std::ofstream out (tmp_file_path, std::ios::binary);
70- out.write (reinterpret_cast <char *>(buf), kBufSize );
71- out.close ();
110+ std::unique_ptr<TempFile> temp =
111+ std::make_unique<TempFile>(reinterpret_cast <char *>(buf), kBufSize );
72112
73113 MemoryMappedFile mf;
74- ASSERT_EQ (mf.length (), 0 );
75- ASSERT_EQ (mf.data (), nullptr );
76- bool open_result = mf.open (tmp_file_path.c_str ());
77- ASSERT_TRUE (open_result);
114+ EXPECT_EQ (mf.length (), 0 );
115+ EXPECT_EQ (mf.data (), nullptr );
116+ EXPECT_FALSE (mf.isOpen ());
117+ bool open_result = mf.open (temp->path ());
118+ EXPECT_TRUE (open_result);
119+ EXPECT_TRUE (mf.isOpen ());
78120
79121 EXPECT_EQ (mf.length (), kBufSize );
80122 EXPECT_TRUE (mf.data () != nullptr );
@@ -83,25 +125,36 @@ TEST(MemoryMappedFileTest, BasicFunctionalities) {
83125 mf.close ();
84126 EXPECT_EQ (mf.length (), 0 );
85127 EXPECT_EQ (mf.data (), nullptr );
128+ EXPECT_FALSE (mf.isOpen ());
86129
87130 // Should be a no-op.
88131 mf.close ();
89132
90133 MemoryMappedFile mf2;
91- open_result = mf2.open (tmp_file_path. c_str ());
134+ open_result = mf2.open (temp-> path ());
92135 EXPECT_TRUE (open_result);
136+ EXPECT_EQ (mf2.length (), kBufSize );
93137 EXPECT_TRUE (mf2.data () != nullptr );
138+ EXPECT_TRUE (mf2.isOpen ());
94139
95140 MemoryMappedFile mf3 (std::move (mf2));
141+ EXPECT_EQ (mf2.length (), 0 );
96142 EXPECT_TRUE (mf2.data () == nullptr );
143+ EXPECT_EQ (mf3.length (), kBufSize );
97144 EXPECT_TRUE (mf3.data () != nullptr );
145+ EXPECT_FALSE (mf2.isOpen ());
146+ EXPECT_TRUE (mf3.isOpen ());
98147
99148 MemoryMappedFile mf4 = std::move (mf3);
149+ EXPECT_EQ (mf3.length (), 0 );
100150 EXPECT_TRUE (mf3.data () == nullptr );
151+ EXPECT_EQ (mf4.length (), kBufSize );
101152 EXPECT_TRUE (mf4.data () != nullptr );
153+ EXPECT_FALSE (mf3.isOpen ());
154+ EXPECT_TRUE (mf4.isOpen ());
102155
103156 // Flip a byte of the underlying file. The map should reflect that.
104- FILE * f = fopen (tmp_file_path. c_str (), " r+b" );
157+ FILE * f = fopen (temp-> path (), " r+b" );
105158 EXPECT_NE (f, nullptr );
106159 EXPECT_NE (fputc (~buf[0 ], f), EOF );
107160 EXPECT_EQ (fclose (f), 0 );
@@ -112,19 +165,23 @@ TEST(MemoryMappedFileTest, BasicFunctionalities) {
112165
113166 mf4.close ();
114167 EXPECT_TRUE (mf4.data () == nullptr );
168+ EXPECT_FALSE (mf4.isOpen ());
115169
116- std::filesystem::remove (tmp_file_path);
117170 delete[] buf;
118171
172+ std::string oldPath = temp->path ();
173+ temp = nullptr ;
174+
119175 // Opening a non-existence file.
120176 MemoryMappedFile mf5;
121- open_result = mf5.open (tmp_file_path .c_str ());
177+ open_result = mf5.open (oldPath .c_str ());
122178 EXPECT_FALSE (open_result);
123179 EXPECT_EQ (mf5.length (), 0 );
124180 EXPECT_EQ (mf5.data (), nullptr );
181+ EXPECT_FALSE (mf5.isOpen ());
125182}
126183
127- TEST (MemoryMappedFileTest, EmptyFile ) {
184+ TEST (MemoryMappedFileTest, OpenFailureOnEmptyFile ) {
128185 std::filesystem::path tmp_file_path =
129186 std::filesystem::temp_directory_path () /
130187 " org.openvanilla.mcbopomofo.memorymappedfiletest-empty-file" ;
@@ -134,33 +191,30 @@ TEST(MemoryMappedFileTest, EmptyFile) {
134191
135192 MemoryMappedFile mf;
136193 EXPECT_FALSE (mf.open (tmp_file_path.c_str ()));
194+ EXPECT_FALSE (mf.isOpen ());
137195 EXPECT_EQ (mf.length (), 0 );
138196 EXPECT_EQ (mf.data (), nullptr );
139197
140198 mf.close ();
141199 EXPECT_EQ (mf.length (), 0 );
142200 EXPECT_EQ (mf.data (), nullptr );
201+ EXPECT_FALSE (mf.isOpen ());
143202
144203 std::filesystem::remove (tmp_file_path);
145204}
146205
147- TEST (MemoryMappedFileTest, MmapFailure) {
148- std::filesystem::path tmp_dir_path =
149- std::filesystem::temp_directory_path () /
150- " org.openvanilla.mcbopomofo.memorymappedfiletest-mmap-failure" ;
151- std::filesystem::remove_all (tmp_dir_path);
152- ASSERT_TRUE (std::filesystem::create_directory (tmp_dir_path));
153-
206+ TEST (MemoryMappedFileTest, OpenFailureOnDirectory) {
207+ TempDir dir;
154208 MemoryMappedFile mf;
155- EXPECT_FALSE (mf.open (tmp_dir_path.c_str ()));
209+ EXPECT_FALSE (mf.open (dir.path ()));
210+ EXPECT_FALSE (mf.isOpen ());
156211 EXPECT_EQ (mf.length (), 0 );
157212 EXPECT_EQ (mf.data (), nullptr );
158213
159214 mf.close ();
160215 EXPECT_EQ (mf.length (), 0 );
161216 EXPECT_EQ (mf.data (), nullptr );
162-
163- std::filesystem::remove_all (tmp_dir_path);
217+ EXPECT_FALSE (mf.isOpen ());
164218}
165219
166220} // namespace McBopomofo
0 commit comments