1//
2// DirectoryIteratorsTest.cpp
3//
4// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
5// and Contributors.
6//
7// SPDX-License-Identifier: BSL-1.0
8//
9
10
11#include "DirectoryIteratorsTest.h"
12#include "Poco/CppUnit/TestCaller.h"
13#include "Poco/CppUnit/TestSuite.h"
14#include "Poco/DirectoryIterator.h"
15#include "Poco/SortedDirectoryIterator.h"
16#include "Poco/RecursiveDirectoryIterator.h"
17#include "Poco/FileStream.h"
18#include "Poco/Environment.h"
19#include "Poco/Exception.h"
20
21#include <iostream>
22
23#if defined(POCO_OS_FAMILY_UNIX)
24#include <errno.h>
25#include <sys/stat.h>
26#endif
27
28using namespace Poco;
29
30
31#if defined(POCO_OS_FAMILY_UNIX)
32
33static void setReadable(const std::string& path, bool flag)
34{
35 poco_assert (!path.empty());
36
37 struct stat st;
38 if (stat(path.c_str(), &st) != 0)
39 {
40 throw FileException("stat error", path, errno);
41 }
42 mode_t mode;
43 if (flag)
44 {
45 mode = st.st_mode | S_IRUSR | S_IRGRP | S_IROTH;
46 }
47 else
48 {
49 mode_t rmask = S_IRUSR | S_IRGRP | S_IROTH;
50 mode = st.st_mode & ~rmask;
51 }
52 if (chmod(path.c_str(), mode) != 0)
53 {
54 throw FileException("chmod", path, errno);
55 }
56}
57
58#else
59
60static void setReadable(const std::string& path, bool flag)
61{
62 poco_assert (!path.empty());
63}
64
65#endif
66
67
68class TemporarilyHidePath
69{
70public:
71 TemporarilyHidePath(std::string path)
72 : _path(path)
73 {
74 setReadable(_path, false);
75 }
76
77 ~TemporarilyHidePath()
78 {
79 setReadable(_path, true);
80 }
81private:
82 std::string _path;
83};
84
85
86DirectoryIteratorsTest::DirectoryIteratorsTest(const std::string& name):
87 CppUnit::TestCase(name)
88{
89}
90
91
92DirectoryIteratorsTest::~DirectoryIteratorsTest()
93{
94}
95
96
97void DirectoryIteratorsTest::testDirectoryIterator()
98{
99 Path p = path();
100 DirectoryIterator dirIterator(p);
101 DirectoryIterator end;
102 std::vector<std::string> result;
103 std::string file;
104
105 while (dirIterator != end)
106 {
107 file = dirIterator->path();
108 ++dirIterator;
109 result.push_back(file);
110 }
111
112 assertEquals(7, (long) result.size());
113}
114
115
116void DirectoryIteratorsTest::testSortedDirectoryIterator()
117{
118 Path p = path();
119
120 SortedDirectoryIterator dirIterator(p);
121 SortedDirectoryIterator end;
122 std::vector<std::string> result;
123 std::string file;
124
125 while (dirIterator != end)
126 {
127 file = Path(dirIterator->path()).getFileName();
128 ++dirIterator;
129 result.push_back(file);
130 }
131
132 assertEquals(7, (long) result.size());
133 assertEquals("first", result[0]);
134 assertEquals("1", result[1]);
135 assertEquals("2", result[2]);
136 assertEquals("A", result[3]);
137 assertEquals("B", result[4]);
138 assertEquals("c", result[5]);
139 assertEquals("d", result[6]);
140}
141
142
143void DirectoryIteratorsTest::testSimpleRecursiveDirectoryIterator()
144{
145 Path p = path();
146 SimpleRecursiveDirectoryIterator dirIterator(p);
147 SimpleRecursiveDirectoryIterator end;
148 std::vector<std::string> result;
149 std::string file;
150
151 while (dirIterator != end)
152 {
153 file = dirIterator->path();
154 ++dirIterator;
155 result.push_back(file);
156 }
157
158 assertEquals(20, (long) result.size());
159}
160
161
162void DirectoryIteratorsTest::testSimpleRecursiveDirectoryIteratorOnError()
163{
164 Path p = path();
165 SimpleRecursiveDirectoryIterator dirIterator(p);
166 dirIterator.onError(*this, &DirectoryIteratorsTest::onError);
167 SimpleRecursiveDirectoryIterator end;
168 std::vector<std::string> result;
169 std::string file;
170
171 Path second(p);
172 second.pushDirectory("first");
173 second.pushDirectory("second");
174 std::string errorPath(second.toString());
175 TemporarilyHidePath hidePath(errorPath);
176
177 while (dirIterator != end)
178 {
179 file = dirIterator->path();
180 ++dirIterator;
181 result.push_back(file);
182 }
183
184#if defined(POCO_OS_FAMILY_UNIX)
185 try
186 {
187 // this test can't work for root
188 if (Environment::get("USER") != "root")
189 {
190 assertTrue (_onErrorPath.size() > 0);
191 if (second.separator() != *_onErrorPath.rbegin())
192 _onErrorPath += second.separator();
193 if (second.separator() != *errorPath.rbegin())
194 errorPath += second.separator();
195 assertEquals(_onErrorPath, errorPath);
196 assertEquals(14, (long) result.size());
197 }
198 }
199 catch (NotFoundException&) { }
200#else
201 assertEquals(20, (long) result.size());
202#endif
203}
204
205
206void DirectoryIteratorsTest::testSiblingsFirstRecursiveDirectoryIterator()
207{
208 Path p = path();
209 SiblingsFirstRecursiveDirectoryIterator dirIterator(p);
210 SiblingsFirstRecursiveDirectoryIterator end;
211 std::vector<std::string> result;
212 std::string file;
213
214 while (dirIterator != end)
215 {
216 file = dirIterator->path();
217 ++dirIterator;
218 result.push_back(file);
219 }
220
221 assertEquals(20, (long) result.size());
222}
223
224
225void DirectoryIteratorsTest::testSiblingsFirstRecursiveDirectoryIteratorOnError()
226{
227 Path p = path();
228 SiblingsFirstRecursiveDirectoryIterator dirIterator(p);
229 dirIterator.onError(*this, &DirectoryIteratorsTest::onError);
230 SimpleRecursiveDirectoryIterator end;
231 std::vector<std::string> result;
232 std::string file;
233
234 Path first(p);
235 first.pushDirectory("first");
236 std::string errorPath(first.toString());
237 TemporarilyHidePath hidePath(errorPath);
238
239 while (dirIterator != end)
240 {
241 file = dirIterator->path();
242 ++dirIterator;
243 result.push_back(file);
244 }
245
246#if defined(POCO_OS_FAMILY_UNIX)
247 try
248 {
249 // this test can't work for root
250 if (Environment::get("USER") != "root")
251 {
252 assertTrue (_onErrorPath.size() > 0);
253 if (first.separator() != *_onErrorPath.rbegin())
254 _onErrorPath += first.separator();
255 if (first.separator() != *errorPath.rbegin())
256 errorPath += first.separator();
257 assertEquals(_onErrorPath, errorPath);
258 assertEquals(7, (long) result.size());
259 }
260 }
261 catch (NotFoundException&) { }
262#else
263 assertEquals(20, (long) result.size());
264#endif
265}
266
267
268void DirectoryIteratorsTest::setUp()
269{
270 File d(path());
271 if (d.exists()) d.remove(true);
272
273 /*
274 Build Directory Tree like this:
275
276 DirectoryIteratorsTest
277 |-- 1
278 |-- 2
279 |-- A
280 |-- B
281 |-- c
282 |-- d
283 `-- first
284 |-- 1
285 |-- 2
286 |-- A
287 |-- B
288 |-- c
289 |-- d
290 `-- second
291 |-- 1
292 |-- 2
293 |-- A
294 |-- B
295 |-- c
296 `-- d
297
298 2 directories, 18 files
299 */
300 Path p = path();
301 createSubdir(p);
302
303 p.pushDirectory("first");
304 createSubdir(p);
305
306 p.pushDirectory("second");
307 createSubdir(p);
308}
309
310
311void DirectoryIteratorsTest::createSubdir(Path& p)
312{
313 File d(p);
314 d.createDirectories();
315 FileStream f1(p.toString() + "d");
316 FileStream f2(p.toString() + "1");
317 FileStream f3(p.toString() + "A");
318 FileStream f4(p.toString() + "2");
319 FileStream f5(p.toString() + "B");
320 FileStream f6(p.toString() + "c");
321}
322
323
324void DirectoryIteratorsTest::onError(const void* pSender, const std::string& path)
325{
326 _onErrorPath = path;
327}
328
329
330void DirectoryIteratorsTest::tearDown()
331{
332 try
333 {
334 File d(path());
335 d.remove(true);
336 }
337 catch (...)
338 {
339 }
340}
341
342
343Poco::Path DirectoryIteratorsTest::path() const
344{
345 Path p(Path::current());
346 p.pushDirectory("DirectoryIteratorsTest");
347 return p;
348}
349
350
351CppUnit::Test* DirectoryIteratorsTest::suite()
352{
353 CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("DirectoryIteratorsTest");
354
355 CppUnit_addTest(pSuite, DirectoryIteratorsTest, testDirectoryIterator);
356 CppUnit_addTest(pSuite, DirectoryIteratorsTest, testSortedDirectoryIterator);
357 CppUnit_addTest(pSuite, DirectoryIteratorsTest, testSimpleRecursiveDirectoryIterator);
358 CppUnit_addTest(pSuite, DirectoryIteratorsTest, testSimpleRecursiveDirectoryIteratorOnError);
359 CppUnit_addTest(pSuite, DirectoryIteratorsTest, testSiblingsFirstRecursiveDirectoryIterator);
360 CppUnit_addTest(pSuite, DirectoryIteratorsTest, testSiblingsFirstRecursiveDirectoryIteratorOnError);
361
362 return pSuite;
363}
364