1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <inttypes.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11
12 #include <fbl/string_printf.h>
13 #include <fbl/unique_fd.h>
14 #include <fuzz-utils/path.h>
15 #include <unittest/unittest.h>
16 #include <zircon/syscalls.h>
17
18 #include "fixture.h"
19
20 namespace fuzzing {
21 namespace testing {
22 namespace {
23
24 // |fuzzing::testing::PathFixture| creates several empty files and directories for use in testing
25 // |fuzzing::Path|.
26 class PathFixture : public Fixture {
27 public:
Create()28 bool Create() override {
29 BEGIN_HELPER;
30 ASSERT_TRUE(Fixture::Create());
31 ASSERT_TRUE(CreateFile("foo/ba/r", nullptr));
32 ASSERT_TRUE(CreateFile("foo/ba/z/qu/x", "hello world"));
33 ASSERT_TRUE(CreateDirectory("foo/ba/z/qu/ux"));
34 END_HELPER;
35 }
36 };
37
TestJoin()38 bool TestJoin() {
39 BEGIN_TEST;
40
41 Path path;
42 EXPECT_STR_EQ(path.c_str(), "/");
43
44 path.Reset();
45 fbl::String str = path.Join("");
46 EXPECT_STR_EQ(path.c_str(), "/");
47
48 path.Reset();
49 str = path.Join("tmp");
50 EXPECT_STR_EQ(str.c_str(), "/tmp");
51
52 str = path.Join("/foo");
53 EXPECT_STR_EQ(str.c_str(), "/foo");
54
55 str = path.Join("bar/");
56 EXPECT_STR_EQ(str.c_str(), "/bar");
57
58 str = path.Join("//baz//");
59 EXPECT_STR_EQ(str.c_str(), "/baz");
60
61 path.Reset();
62 str = path.Join("tmp//foo//bar//baz");
63 EXPECT_STR_EQ(str.c_str(), "/tmp/foo/bar/baz");
64
65 END_TEST;
66 }
67
TestPushAndPop()68 bool TestPushAndPop() {
69 BEGIN_TEST;
70 PathFixture fixture;
71 ASSERT_TRUE(fixture.Create());
72
73 Path path;
74 EXPECT_STR_EQ(path.c_str(), "/");
75
76 EXPECT_EQ(ZX_OK, path.Push("tmp"));
77 EXPECT_STR_EQ(path.c_str(), "/tmp/");
78
79 path.Pop();
80 EXPECT_STR_EQ(path.c_str(), "/");
81
82 EXPECT_EQ(ZX_OK, path.Push("//tmp"));
83 EXPECT_STR_EQ(path.c_str(), "/tmp/");
84
85 path.Pop();
86 EXPECT_STR_EQ(path.c_str(), "/");
87
88 EXPECT_EQ(ZX_OK, path.Push("tmp//"));
89 EXPECT_STR_EQ(path.c_str(), "/tmp/");
90
91 path.Pop();
92 EXPECT_STR_EQ(path.c_str(), "/");
93
94 EXPECT_EQ(ZX_OK, path.Push("//tmp//"));
95 EXPECT_STR_EQ(path.c_str(), "/tmp/");
96
97 EXPECT_NE(ZX_OK, path.Push(""));
98 EXPECT_STR_EQ(path.c_str(), "/tmp/");
99
100 EXPECT_NE(ZX_OK, path.Push("f"));
101
102 path.Pop();
103 EXPECT_STR_EQ(path.c_str(), "/");
104
105 path.Pop();
106 EXPECT_STR_EQ(path.c_str(), "/");
107
108 path.Reset();
109 EXPECT_EQ(ZX_OK, path.Push(fixture.path()));
110 EXPECT_CSTR_EQ(path, fixture.path());
111
112 EXPECT_EQ(ZX_OK, path.Push("foo/ba"));
113 EXPECT_CSTR_EQ(path, fixture.path("foo/ba/"));
114
115 EXPECT_NE(ZX_OK, path.Push("r"));
116 EXPECT_CSTR_EQ(path, fixture.path("foo/ba/"));
117
118 EXPECT_EQ(ZX_OK, path.Push("z/qu/ux/"));
119 EXPECT_CSTR_EQ(path, fixture.path("foo/ba/z/qu/ux/"));
120
121 path.Pop();
122 EXPECT_CSTR_EQ(path, fixture.path("foo/ba/"));
123
124 path.Pop();
125 EXPECT_CSTR_EQ(path, fixture.path());
126
127 path.Pop();
128 EXPECT_STR_EQ(path.c_str(), "/");
129
130 END_TEST;
131 }
132
TestGetSizeAndExists()133 bool TestGetSizeAndExists() {
134 BEGIN_TEST;
135 PathFixture fixture;
136 ASSERT_TRUE(fixture.Create());
137
138 Path path;
139 ASSERT_EQ(ZX_OK, path.Push(fixture.path("foo/ba/")));
140
141 size_t size;
142 EXPECT_EQ(ZX_OK, path.GetSize("r", &size));
143 EXPECT_EQ(size, 0);
144
145 // Non-existent and not file
146 EXPECT_NE(ZX_OK, path.GetSize("q", &size));
147 EXPECT_NE(ZX_OK, path.GetSize("z", &size));
148
149 // +1 is for null terminator
150 EXPECT_EQ(ZX_OK, path.GetSize("z/qu/x", &size));
151 EXPECT_EQ(size, static_cast<size_t>(strlen("hello world") + 1));
152
153 EXPECT_TRUE(path.IsFile("r"));
154 EXPECT_FALSE(path.IsFile("q"));
155 EXPECT_FALSE(path.IsFile("z"));
156 EXPECT_TRUE(path.IsFile("z/qu/x"));
157
158 END_TEST;
159 }
160
TestList()161 bool TestList() {
162 BEGIN_TEST;
163 PathFixture fixture;
164 ASSERT_TRUE(fixture.Create());
165
166 Path path;
167 ASSERT_EQ(ZX_OK, path.Push(fixture.path("foo")));
168
169 fbl::unique_ptr<StringList> list;
170 list = path.List();
171 EXPECT_STR_EQ(list->first(), "ba");
172 EXPECT_NULL(list->next());
173
174 ASSERT_EQ(ZX_OK, path.Push("ba"));
175 list = path.List();
176
177 EXPECT_EQ(list->length(), 2);
178 list->erase_if("r");
179 list->erase_if("z");
180 EXPECT_TRUE(list->is_empty());
181
182 ASSERT_EQ(ZX_OK, path.Push("z/qu/ux"));
183 list = path.List();
184 EXPECT_TRUE(list->is_empty());
185
186 END_TEST;
187 }
188
TestEnsureAndRemove()189 bool TestEnsureAndRemove() {
190 BEGIN_TEST;
191 PathFixture fixture;
192 ASSERT_TRUE(fixture.Create());
193
194 Path path;
195 ASSERT_EQ(ZX_OK, path.Push(fixture.path()));
196 ASSERT_EQ(ZX_OK, path.Push("foo/ba/z/qu"));
197
198 EXPECT_EQ(ZX_OK, path.Ensure(""));
199 EXPECT_NE(ZX_OK, path.Ensure("x"));
200 EXPECT_EQ(ZX_OK, path.Ensure("ux"));
201 EXPECT_EQ(ZX_OK, path.Ensure("corge"));
202 EXPECT_EQ(ZX_OK, path.Ensure("g/rault"));
203 EXPECT_EQ(ZX_OK, path.Ensure("g/arply"));
204
205 EXPECT_NE(ZX_OK, path.Remove(""));
206 EXPECT_EQ(ZX_OK, path.Remove("a"));
207
208 EXPECT_EQ(ZX_OK, path.Remove("x"));
209 EXPECT_NE(ZX_OK, path.Push("x"));
210
211 EXPECT_EQ(ZX_OK, path.Remove("corge"));
212 EXPECT_NE(ZX_OK, path.Push("corge"));
213
214 EXPECT_EQ(ZX_OK, path.Remove("g"));
215 EXPECT_NE(ZX_OK, path.Push("g"));
216
217 path.Pop();
218 EXPECT_EQ(ZX_OK, path.Remove("foo"));
219 EXPECT_NE(ZX_OK, path.Push("foo"));
220
221 END_TEST;
222 }
223
TestRename()224 bool TestRename() {
225 BEGIN_TEST;
226 BEGIN_TEST;
227 PathFixture fixture;
228 ASSERT_TRUE(fixture.Create());
229
230 Path path;
231 ASSERT_EQ(ZX_OK, path.Push(fixture.path("foo/ba")));
232
233 EXPECT_NE(ZX_OK, path.Rename("", "empty"));
234 EXPECT_NE(ZX_OK, path.Rename("empty", ""));
235
236 EXPECT_NE(ZX_OK, path.Rename("missing", "found"));
237
238 fbl::unique_fd fd(open(fixture.path("foo/ba/r").c_str(), O_RDWR));
239 EXPECT_TRUE(!!fd);
240 fd.reset(open(fixture.path("foo/ba/s").c_str(), O_RDWR));
241 EXPECT_FALSE(!!fd);
242
243 EXPECT_EQ(ZX_OK, path.Rename("r", "s"));
244 fd.reset(open(fixture.path("foo/ba/r").c_str(), O_RDWR));
245 EXPECT_FALSE(!!fd);
246 fd.reset(open(fixture.path("foo/ba/s").c_str(), O_RDWR));
247 EXPECT_TRUE(!!fd);
248
249 EXPECT_EQ(ZX_OK, path.Rename("s", "r"));
250 fd.reset(open(fixture.path("foo/ba/r").c_str(), O_RDWR));
251 EXPECT_TRUE(!!fd);
252 fd.reset(open(fixture.path("foo/ba/s").c_str(), O_RDWR));
253 EXPECT_FALSE(!!fd);
254
255 EXPECT_EQ(ZX_OK, path.Rename("z", "y"));
256 EXPECT_NE(ZX_OK, path.Push("z/qu/ux"));
257 EXPECT_EQ(ZX_OK, path.Push("y/qu/ux"));
258
259 path.Pop();
260 EXPECT_EQ(ZX_OK, path.Rename("y", "z"));
261 EXPECT_NE(ZX_OK, path.Push("y/qu/ux"));
262 EXPECT_EQ(ZX_OK, path.Push("z/qu/ux"));
263
264 END_TEST;
265 }
266
TestReset()267 bool TestReset() {
268 BEGIN_TEST;
269 PathFixture fixture;
270 ASSERT_TRUE(fixture.Create());
271
272 Path path;
273 ASSERT_EQ(ZX_OK, path.Push(fixture.path()));
274
275 path.Reset();
276 EXPECT_STR_EQ(path.c_str(), "/");
277
278 END_TEST;
279 }
280
281 BEGIN_TEST_CASE(PathTest)
282 RUN_TEST(TestJoin)
283 RUN_TEST(TestPushAndPop)
284 RUN_TEST(TestGetSizeAndExists)
285 RUN_TEST(TestList)
286 RUN_TEST(TestEnsureAndRemove)
287 RUN_TEST(TestRename)
288 RUN_TEST(TestReset)
289 END_TEST_CASE(PathTest)
290
291 } // namespace
292 } // namespace testing
293 } // namespace fuzzing
294