1/*
2 * Copyright 2017, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "KPathTest.h"
8
9#include <stdlib.h>
10#include <string.h>
11
12#include <fs/KPath.h>
13
14#include <cppunit/TestCaller.h>
15#include <cppunit/TestSuite.h>
16
17
18typedef void* mutex;
19
20
21// Kernel stubs
22
23
24extern "C" team_id
25team_get_kernel_team_id(void)
26{
27	return 0;
28}
29
30
31extern "C" team_id
32team_get_current_team_id(void)
33{
34	return 0;
35}
36
37
38extern "C" status_t
39vfs_normalize_path(const char* path, char* buffer, size_t bufferSize,
40	bool traverseLink, bool kernel)
41{
42	return B_NOT_SUPPORTED;
43}
44
45
46// #pragma mark - DEBUG only
47
48
49extern "C" void*
50memalign_etc(size_t alignment, size_t size, uint32 flags)
51{
52	return malloc(size);
53}
54
55
56extern "C" status_t
57_mutex_lock(mutex* lock, void* locker)
58{
59	return B_OK;
60}
61
62
63extern "C" status_t
64_mutex_trylock(mutex* lock)
65{
66	return B_OK;
67}
68
69
70extern "C" void
71_mutex_unlock(mutex* lock)
72{
73}
74
75
76// #pragma mark -
77
78
79KPathTest::KPathTest()
80{
81}
82
83
84KPathTest::~KPathTest()
85{
86}
87
88
89void
90KPathTest::TestSetToAndPath()
91{
92	KPath path;
93	status_t status = path.InitCheck();
94	CPPUNIT_ASSERT_MESSAGE("1. ", status == B_OK);
95
96	status = path.SetTo("a/b/c");
97	CPPUNIT_ASSERT_MESSAGE("2. ", status == B_OK);
98	CPPUNIT_ASSERT(strcmp(path.Path(), "a/b/c") == 0);
99	CPPUNIT_ASSERT(path.Length() == 5);
100	CPPUNIT_ASSERT(path.BufferSize() == B_PATH_NAME_LENGTH + 1);
101
102	status = path.SetPath("abc/def");
103	CPPUNIT_ASSERT_MESSAGE("3. ", status == B_OK);
104	CPPUNIT_ASSERT(strcmp(path.Path(), "abc/def") == 0);
105	CPPUNIT_ASSERT(path.Length() == 7);
106	CPPUNIT_ASSERT(path.BufferSize() == B_PATH_NAME_LENGTH + 1);
107
108	status = path.SetTo("a/b/c", false, 10);
109	CPPUNIT_ASSERT_MESSAGE("4. ", status == B_OK);
110	CPPUNIT_ASSERT(strcmp(path.Path(), "a/b/c") == 0);
111	CPPUNIT_ASSERT(path.Length() == 5);
112	CPPUNIT_ASSERT(path.BufferSize() == 10);
113
114	status = path.SetPath("sorry/i'm/too/long");
115	CPPUNIT_ASSERT(status == B_BUFFER_OVERFLOW);
116	CPPUNIT_ASSERT(strcmp(path.Path(), "a/b/c") == 0);
117	CPPUNIT_ASSERT(path.Length() == 5);
118
119	status = path.SetTo(NULL, KPath::DEFAULT, SIZE_MAX);
120	CPPUNIT_ASSERT(status == B_NO_MEMORY);
121}
122
123
124void
125KPathTest::TestLazyAlloc()
126{
127	KPath path(NULL, KPath::LAZY_ALLOC);
128	CPPUNIT_ASSERT(path.Path() == NULL);
129	CPPUNIT_ASSERT(path.Length() == 0);
130	CPPUNIT_ASSERT(path.BufferSize() == B_PATH_NAME_LENGTH + 1);
131	CPPUNIT_ASSERT(path.InitCheck() == B_OK);
132
133	path.SetPath("/b");
134	CPPUNIT_ASSERT(path.Path() != NULL);
135	CPPUNIT_ASSERT(strcmp(path.Path(), "/b") == 0);
136	CPPUNIT_ASSERT(path.Length() == 2);
137	CPPUNIT_ASSERT(path.BufferSize() == B_PATH_NAME_LENGTH + 1);
138
139	KPath second("yo", KPath::LAZY_ALLOC);
140	CPPUNIT_ASSERT(second.Path() != NULL);
141	CPPUNIT_ASSERT(strcmp(second.Path(), "yo") == 0);
142	CPPUNIT_ASSERT(second.Length() == 2);
143	CPPUNIT_ASSERT(second.BufferSize() == B_PATH_NAME_LENGTH + 1);
144
145	status_t status = path.SetTo(NULL, KPath::LAZY_ALLOC, SIZE_MAX);
146	CPPUNIT_ASSERT(status == B_OK);
147	status = path.SetPath("test");
148	CPPUNIT_ASSERT(status == B_NO_MEMORY);
149	CPPUNIT_ASSERT(path.InitCheck() == B_NO_MEMORY);
150}
151
152
153void
154KPathTest::TestLeaf()
155{
156	KPath path("a");
157	CPPUNIT_ASSERT(strcmp(path.Path(), "a") == 0);
158	CPPUNIT_ASSERT(strcmp(path.Leaf(), "a") == 0);
159
160	path.SetTo("");
161	CPPUNIT_ASSERT(strcmp(path.Path(), "") == 0);
162	CPPUNIT_ASSERT(strcmp(path.Leaf(), "") == 0);
163
164	path.SetTo("/");
165	CPPUNIT_ASSERT(strcmp(path.Path(), "/") == 0);
166	CPPUNIT_ASSERT(strcmp(path.Leaf(), "") == 0);
167
168	path.SetTo("a/b");
169	CPPUNIT_ASSERT(strcmp(path.Path(), "a/b") == 0);
170	CPPUNIT_ASSERT(strcmp(path.Leaf(), "b") == 0);
171
172	path.SetTo("a/b/");
173	CPPUNIT_ASSERT(strcmp(path.Path(), "a/b") == 0);
174	CPPUNIT_ASSERT(strcmp(path.Leaf(), "b") == 0);
175
176	path.SetTo("/a/b//c");
177	CPPUNIT_ASSERT(strcmp(path.Path(), "/a/b//c") == 0);
178	CPPUNIT_ASSERT(strcmp(path.Leaf(), "c") == 0);
179}
180
181
182void
183KPathTest::TestReplaceLeaf()
184{
185	KPath path;
186	status_t status = path.ReplaceLeaf("x");
187	CPPUNIT_ASSERT(status == B_OK);
188
189	path.SetTo("/a/b/c");
190	CPPUNIT_ASSERT(path.Length() == 6);
191
192	status = path.ReplaceLeaf(NULL);
193	CPPUNIT_ASSERT(status == B_OK);
194	CPPUNIT_ASSERT(path.Length() == 4);
195	CPPUNIT_ASSERT(strcmp(path.Path(), "/a/b") == 0);
196
197	status = path.ReplaceLeaf("");
198	CPPUNIT_ASSERT(status == B_OK);
199	CPPUNIT_ASSERT(path.Length() == 2);
200	CPPUNIT_ASSERT(strcmp(path.Path(), "/a") == 0);
201
202	status = path.ReplaceLeaf("c");
203	CPPUNIT_ASSERT(status == B_OK);
204	CPPUNIT_ASSERT(path.Length() == 2);
205	CPPUNIT_ASSERT(strcmp(path.Path(), "/c") == 0);
206}
207
208
209void
210KPathTest::TestRemoveLeaf()
211{
212	KPath path;
213	bool removed = path.RemoveLeaf();
214	CPPUNIT_ASSERT(!removed);
215
216	path.SetTo("a//b/c");
217	removed = path.RemoveLeaf();
218	CPPUNIT_ASSERT_MESSAGE("1. removed", removed);
219	CPPUNIT_ASSERT(strcmp(path.Path(), "a//b") == 0);
220	CPPUNIT_ASSERT(path.Length() == 4);
221
222	removed = path.RemoveLeaf();
223	CPPUNIT_ASSERT_MESSAGE("2. removed", removed);
224	CPPUNIT_ASSERT(strcmp(path.Path(), "a") == 0);
225	CPPUNIT_ASSERT(path.Length() == 1);
226
227	removed = path.RemoveLeaf();
228	CPPUNIT_ASSERT_MESSAGE("3. !removed", !removed);
229	CPPUNIT_ASSERT(strcmp(path.Path(), "a") == 0);
230	CPPUNIT_ASSERT(path.Length() == 1);
231
232	path.SetTo("/a");
233	removed = path.RemoveLeaf();
234	CPPUNIT_ASSERT_MESSAGE("4. removed", removed);
235	CPPUNIT_ASSERT(strcmp(path.Path(), "/") == 0);
236	CPPUNIT_ASSERT(path.Length() == 1);
237
238	removed = path.RemoveLeaf();
239	CPPUNIT_ASSERT_MESSAGE("5. !removed", !removed);
240	CPPUNIT_ASSERT(strcmp(path.Path(), "/") == 0);
241	CPPUNIT_ASSERT(path.Length() == 1);
242}
243
244
245void
246KPathTest::TestAdopt()
247{
248	KPath one("first", false, 10);
249	CPPUNIT_ASSERT(one.InitCheck() == B_OK);
250	CPPUNIT_ASSERT(one.BufferSize() == 10);
251	CPPUNIT_ASSERT(one.Length() == 5);
252	KPath two("second", false, 20);
253	CPPUNIT_ASSERT(two.InitCheck() == B_OK);
254	CPPUNIT_ASSERT(two.BufferSize() == 20);
255
256	one.Adopt(two);
257	CPPUNIT_ASSERT(one.InitCheck() == B_OK);
258	CPPUNIT_ASSERT(one.BufferSize() == 20);
259	CPPUNIT_ASSERT(one.Length() == 6);
260	CPPUNIT_ASSERT(strcmp(one.Path(), "second") == 0);
261	CPPUNIT_ASSERT(two.Length() == 0);
262	CPPUNIT_ASSERT(two.BufferSize() == 0);
263	CPPUNIT_ASSERT(two.InitCheck() == B_NO_INIT);
264
265	two.SetTo(NULL, KPath::LAZY_ALLOC);
266	CPPUNIT_ASSERT(two.InitCheck() == B_OK);
267	CPPUNIT_ASSERT(two.Path() == NULL);
268	CPPUNIT_ASSERT(two.Length() == 0);
269	one.Adopt(two);
270
271	CPPUNIT_ASSERT(two.InitCheck() == B_OK);
272	CPPUNIT_ASSERT(one.Path() == NULL);
273	CPPUNIT_ASSERT(one.Length() == 0);
274	one.SetPath("test");
275	CPPUNIT_ASSERT(one.Path() != NULL);
276	CPPUNIT_ASSERT(strcmp(one.Path(), "test") == 0);
277	CPPUNIT_ASSERT(one.Length() == 4);
278}
279
280
281void
282KPathTest::TestLockBuffer()
283{
284	KPath path;
285	CPPUNIT_ASSERT(path.Path() != NULL);
286	CPPUNIT_ASSERT(path.Length() == 0);
287	char* buffer = path.LockBuffer();
288	CPPUNIT_ASSERT(path.Path() == buffer);
289	strcpy(buffer, "test");
290	CPPUNIT_ASSERT(path.Length() == 0);
291	path.UnlockBuffer();
292	CPPUNIT_ASSERT(path.Length() == 4);
293
294	KPath second(NULL, KPath::LAZY_ALLOC);
295	CPPUNIT_ASSERT(second.Path() == NULL);
296	CPPUNIT_ASSERT(second.Length() == 0);
297	buffer = second.LockBuffer();
298	CPPUNIT_ASSERT(second.Path() == NULL);
299	CPPUNIT_ASSERT(buffer == NULL);
300
301	KPath third(NULL, KPath::LAZY_ALLOC);
302	CPPUNIT_ASSERT(third.Path() == NULL);
303	buffer = third.LockBuffer(true);
304	CPPUNIT_ASSERT(third.Path() != NULL);
305	CPPUNIT_ASSERT(buffer != NULL);
306	strcpy(buffer, "test");
307	CPPUNIT_ASSERT(third.Length() == 0);
308	third.UnlockBuffer();
309	CPPUNIT_ASSERT(third.Length() == 4);
310}
311
312
313void
314KPathTest::TestDetachBuffer()
315{
316	KPath path("test");
317	CPPUNIT_ASSERT(path.InitCheck() == B_OK);
318
319	char* buffer = path.DetachBuffer();
320	CPPUNIT_ASSERT(buffer != NULL);
321	CPPUNIT_ASSERT(strcmp(buffer, "test") == 0);
322
323	CPPUNIT_ASSERT(path.Path() == NULL);
324	CPPUNIT_ASSERT(path.InitCheck() == B_NO_INIT);
325}
326
327
328void
329KPathTest::TestNormalize()
330{
331	// Outside the kernel, we only test the error case.
332	KPath path("test/../out");
333	CPPUNIT_ASSERT(path.InitCheck() == B_OK);
334
335	status_t status = path.Normalize(true);
336	CPPUNIT_ASSERT(status == B_NOT_SUPPORTED);
337	CPPUNIT_ASSERT(path.Path() != NULL);
338	CPPUNIT_ASSERT(path.Path()[0] == '\0');
339	CPPUNIT_ASSERT(path.Path() == path.Leaf());
340
341	status = path.SetTo("test/../in", KPath::NORMALIZE);
342	CPPUNIT_ASSERT(status == B_NOT_SUPPORTED);
343	CPPUNIT_ASSERT(path.Path() != NULL);
344	CPPUNIT_ASSERT(path.Path()[0] == '\0');
345	CPPUNIT_ASSERT(path.Path() == path.Leaf());
346}
347
348
349void
350KPathTest::TestAssign()
351{
352	KPath one("first", false, 10);
353	CPPUNIT_ASSERT(one.Length() == 5);
354	KPath two("second", false, 20);
355
356	two = one;
357	CPPUNIT_ASSERT(strcmp(two.Path(), one.Path()) == 0);
358	CPPUNIT_ASSERT(two.Path() != one.Path());
359	CPPUNIT_ASSERT(two.BufferSize() == one.BufferSize());
360	CPPUNIT_ASSERT(two.Length() == one.Length());
361
362	one = "/whatever";
363	CPPUNIT_ASSERT(one.Length() == 9);
364	CPPUNIT_ASSERT(one.BufferSize() == two.BufferSize());
365	CPPUNIT_ASSERT(strcmp(one.Path(), "/whatever") == 0);
366}
367
368
369void
370KPathTest::TestEquals()
371{
372	KPath a("one");
373	KPath b("two");
374	CPPUNIT_ASSERT_MESSAGE("1.", !(a == b));
375
376	b = a;
377	CPPUNIT_ASSERT_MESSAGE("2.", a == b);
378
379	b = "ones";
380	CPPUNIT_ASSERT_MESSAGE("3.", !(a == b));
381}
382
383
384void
385KPathTest::TestNotEquals()
386{
387	KPath a("one");
388	KPath b("two");
389	CPPUNIT_ASSERT_MESSAGE("1.", a != b);
390
391	b = a;
392	CPPUNIT_ASSERT_MESSAGE("2.", !(a != b));
393
394	b = "ones";
395	CPPUNIT_ASSERT_MESSAGE("3.", a != b);
396}
397
398
399/*static*/ void
400KPathTest::AddTests(BTestSuite& parent)
401{
402	CppUnit::TestSuite& suite = *new CppUnit::TestSuite("KPathTest");
403
404	suite.addTest(new CppUnit::TestCaller<KPathTest>(
405		"KPathTest::TestSetToAndPath", &KPathTest::TestSetToAndPath));
406	suite.addTest(new CppUnit::TestCaller<KPathTest>(
407		"KPathTest::TestLazyAlloc", &KPathTest::TestLazyAlloc));
408	suite.addTest(new CppUnit::TestCaller<KPathTest>(
409		"KPathTest::TestLeaf", &KPathTest::TestLeaf));
410	suite.addTest(new CppUnit::TestCaller<KPathTest>(
411		"KPathTest::TestReplaceLeaf", &KPathTest::TestReplaceLeaf));
412	suite.addTest(new CppUnit::TestCaller<KPathTest>(
413		"KPathTest::TestRemoveLeaf", &KPathTest::TestRemoveLeaf));
414	suite.addTest(new CppUnit::TestCaller<KPathTest>(
415		"KPathTest::TestAdopt", &KPathTest::TestAdopt));
416	suite.addTest(new CppUnit::TestCaller<KPathTest>(
417		"KPathTest::TestLockBuffer", &KPathTest::TestLockBuffer));
418	suite.addTest(new CppUnit::TestCaller<KPathTest>(
419		"KPathTest::TestDetachBuffer", &KPathTest::TestDetachBuffer));
420	suite.addTest(new CppUnit::TestCaller<KPathTest>(
421		"KPathTest::TestNormalize", &KPathTest::TestNormalize));
422	suite.addTest(new CppUnit::TestCaller<KPathTest>(
423		"KPathTest::TestAssign", &KPathTest::TestAssign));
424	suite.addTest(new CppUnit::TestCaller<KPathTest>(
425		"KPathTest::TestEquals", &KPathTest::TestEquals));
426	suite.addTest(new CppUnit::TestCaller<KPathTest>(
427		"KPathTest::TestNotEquals", &KPathTest::TestNotEquals));
428
429	parent.addTest("KPathTest", &suite);
430}
431