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