1#include <iostream>
2#include <platform/dirutils.h>
3#include <cstdlib>
4#include <limits>
5#include <list>
6#include <string>
7#include <cerrno>
8#include <cstring>
9#include <sys/stat.h>
10#include <sys/types.h>
11#include <stdio.h>
12
13#ifdef WIN32
14#define NOMINMAX
15#include <windows.h>
16#include <direct.h>
17static bool CreateDirectory(const std::string &dir) {
18    if (_mkdir(dir.c_str()) != 0) {
19        return false;
20    }
21    return true;
22}
23
24#define PATH_SEPARATOR "\\"
25
26#else
27static bool CreateDirectory(const std::string &dir) {
28   if (mkdir(dir.c_str(), S_IXUSR | S_IWUSR | S_IRUSR) != 0) {
29      return false;
30   }
31   return true;
32}
33
34#define PATH_SEPARATOR "/"
35
36#endif
37
38#undef NDEBUG
39#include <cassert>
40
41int exit_value = EXIT_SUCCESS;
42
43static void expect(const bool exp, const bool val) {
44    if (exp != val) {
45        std::cerr << "Expected " << exp << " got [" << val << "]" << std::endl;
46        exit_value = EXIT_FAILURE;
47    }
48}
49
50static void expect(const std::string &exp, const std::string &val) {
51   if (exp != val) {
52      std::cerr << "Expected " << exp << " got [" << val << "]" << std::endl;
53      exit_value = EXIT_FAILURE;
54   }
55}
56
57static void expect(size_t size, const std::vector<std::string> &vec) {
58   if (vec.size() != size) {
59      std::cerr << "Expected vector of " << size
60                << " elements got [" << vec.size() << "]" << std::endl;
61      exit_value = EXIT_FAILURE;
62   }
63}
64
65static void contains(const std::string &val, const std::vector<std::string> &vec) {
66   std::vector<std::string>::const_iterator ii;
67   for (ii = vec.begin(); ii != vec.end(); ++ii) {
68      if (val == *ii) {
69         return ;
70      }
71   }
72
73   std::cerr << "Expected vector to contain [" << val << "]" << std::endl;
74   for (ii = vec.begin(); ii != vec.end(); ++ii) {
75      std::cerr << "  -> " << *ii << std::endl;
76   }
77   std::cerr << std::endl;
78   exit_value = EXIT_FAILURE;
79}
80
81static std::list<std::string> vfs;
82
83static bool exists(const std::string &path) {
84   struct stat st;
85   return stat(path.c_str(), &st) == 0;
86}
87
88static void testDirname(void) {
89   // Check the simple case
90   expect("foo", cb::io::dirname("foo\\bar"));
91   expect("foo", cb::io::dirname("foo/bar"));
92
93   // Make sure that we remove double an empty chunk
94   expect("foo", cb::io::dirname("foo\\\\bar"));
95   expect("foo", cb::io::dirname("foo//bar"));
96
97   // Make sure that we handle the case without a directory
98   expect(".", cb::io::dirname("bar"));
99   expect(".", cb::io::dirname(""));
100
101   // Absolute directories
102   expect("\\", cb::io::dirname("\\bar"));
103   expect("\\", cb::io::dirname("\\\\bar"));
104   expect("/", cb::io::dirname("/bar"));
105   expect("/", cb::io::dirname("//bar"));
106
107   // Test that we work with multiple directories
108   expect("1/2/3/4/5", cb::io::dirname("1/2/3/4/5/6"));
109   expect("1\\2\\3\\4\\5", cb::io::dirname("1\\2\\3\\4\\5\\6"));
110   expect("1/2\\4/5", cb::io::dirname("1/2\\4/5\\6"));
111}
112
113static void testBasename(void) {
114   expect("bar", cb::io::basename("foo\\bar"));
115   expect("bar", cb::io::basename("foo/bar"));
116   expect("bar", cb::io::basename("foo\\\\bar"));
117   expect("bar", cb::io::basename("foo//bar"));
118   expect("bar", cb::io::basename("bar"));
119   expect("", cb::io::basename(""));
120   expect("bar", cb::io::basename("\\bar"));
121   expect("bar", cb::io::basename("\\\\bar"));
122   expect("bar", cb::io::basename("/bar"));
123   expect("bar", cb::io::basename("//bar"));
124   expect("6", cb::io::basename("1/2/3/4/5/6"));
125   expect("6", cb::io::basename("1\\2\\3\\4\\5\\6"));
126   expect("6", cb::io::basename("1/2\\4/5\\6"));
127}
128
129static void testFindFilesWithPrefix(void) {
130   using namespace cb::io;
131
132   std::vector<std::string> vec = findFilesWithPrefix("fs");
133   expect(1, vec);
134   contains("." PATH_SEPARATOR "fs", vec);
135
136   vec = findFilesWithPrefix("fs", "d");
137   expect(3, vec);
138   contains("fs" PATH_SEPARATOR "d1", vec);
139   contains("fs" PATH_SEPARATOR "d2", vec);
140   contains("fs" PATH_SEPARATOR "d3", vec);
141   vec = findFilesWithPrefix("fs", "1");
142   expect(1, vec);
143   contains("fs" PATH_SEPARATOR "1", vec);
144
145   vec = findFilesWithPrefix("fs", "");
146   expect(vfs.size() - 1, vec);
147
148}
149
150static void testFindFilesContaining(void) {
151   using namespace cb::io;
152   std::vector<std::string> vec = findFilesContaining("fs", "");
153   expect(vfs.size() - 1, vec);
154
155   vec = findFilesContaining("fs", "2");
156   expect(7, vec);
157   contains("fs" PATH_SEPARATOR "d2", vec);
158   contains("fs" PATH_SEPARATOR "e2", vec);
159   contains("fs" PATH_SEPARATOR "f2c", vec);
160   contains("fs" PATH_SEPARATOR "g2", vec);
161   contains("fs" PATH_SEPARATOR "2", vec);
162   contains("fs" PATH_SEPARATOR "2c", vec);
163   contains("fs" PATH_SEPARATOR "2d", vec);
164}
165
166static void testRemove(void) {
167   fclose(fopen("test-file", "w"));
168   if (!cb::io::rmrf("test-file")) {
169      std::cerr << "expected to delete existing file" << std::endl;
170   }
171   if (cb::io::rmrf("test-file")) {
172      std::cerr << "Didn't expected to delete non-existing file" << std::endl;
173   }
174
175   if (!cb::io::rmrf("fs")) {
176      std::cerr << "Expected to nuke the entire fs directory recursively" << std::endl;
177   }
178}
179
180static void testIsDirectory(void) {
181    using namespace cb::io;
182#ifdef WIN32
183    expect(true, isDirectory("c:\\"));
184#else
185    expect(true, isDirectory("/"));
186#endif
187    expect(true, isDirectory("."));
188    expect(false, isDirectory("/it/would/suck/if/this/exists"));
189    FILE *fp = fopen("isDirectoryTest", "w");
190    if (fp == NULL) {
191        std::cerr << "Failed to create test file" << std::endl;
192        exit_value = EXIT_FAILURE;
193    } else {
194        using namespace std;
195        fclose(fp);
196        expect(false, isDirectory("isDirectoryTest"));
197        remove("isDirectoryTest");
198    }
199}
200
201static void testIsFile(void) {
202   using namespace cb::io;
203   expect(false, isFile("."));
204   FILE* fp = fopen("plainfile", "w");
205   if (fp == nullptr) {
206      std::cerr << "Failed to create test file" << std::endl;
207      exit_value = EXIT_FAILURE;
208   } else {
209      fclose(fp);
210      expect(true, isFile("plainfile"));
211      rmrf("plainfile");
212   }
213}
214
215static void testMkdirp(void) {
216    using namespace cb::io;
217
218#ifndef WIN32
219    expect(false, mkdirp("/it/would/suck/if/I/could/create/this"));
220#endif
221    expect(true, mkdirp("."));
222    expect(true, mkdirp("/"));
223    expect(true, mkdirp("foo/bar"));
224    expect(true, isDirectory("foo/bar"));
225    rmrf("foo");
226}
227
228static void testGetCurrentDirectory() {
229   try {
230      auto cwd = cb::io::getcwd();
231      // I can't really determine the correct value here, but it shouldn't be
232      // empty ;-)
233      if (cwd.empty()) {
234         std::cerr << "FAIL: cwd should not be an empty string" << std::endl;
235         exit(EXIT_FAILURE);
236      }
237   } catch (const std::exception& ex) {
238      std::cerr << "FAIL: " << ex.what() << std::endl;
239      exit(EXIT_FAILURE);
240   }
241}
242
243static void testCbMktemp() {
244   auto filename = cb::io::mktemp("foo");
245   if (filename.empty()) {
246      std::cerr << "FAIL: Expected to create tempfile without mask"
247                << std::endl;
248      exit(EXIT_FAILURE);
249   }
250
251   if (!cb::io::isFile(filename)) {
252      std::cerr << "FAIL: Expected mktemp to create file" << std::endl;
253      exit(EXIT_FAILURE);
254   }
255
256   if (!cb::io::rmrf(filename)) {
257      std::cerr << "FAIL: failed to remove temporary file" << std::endl;
258      exit(EXIT_FAILURE);
259   }
260
261   filename = cb::io::mktemp("barXXXXXX");
262   if (filename.empty()) {
263      std::cerr << "FAIL: Expected to create tempfile with mask"
264                << std::endl;
265      exit(EXIT_FAILURE);
266   }
267
268   if (!cb::io::isFile(filename)) {
269      std::cerr << "FAIL: Expected mktemp to create file" << std::endl;
270      exit(EXIT_FAILURE);
271   }
272
273   if (!cb::io::rmrf(filename)) {
274      std::cerr << "FAIL: failed to remove temporary file" << std::endl;
275      exit(EXIT_FAILURE);
276   }
277}
278
279void testMaximizeFileDescriptors() {
280   auto limit = cb::io::maximizeFileDescriptors(32);
281   if (limit <= 32) {
282      std::cerr << "FAIL: I should be able to set it to at least 32"
283                << std::endl;
284      exit(EXIT_FAILURE);
285   }
286
287   limit = cb::io::maximizeFileDescriptors(std::numeric_limits<uint32_t>::max());
288   if (limit != std::numeric_limits<uint32_t>::max()) {
289      // windows don't have a max limit, and that could be for other platforms
290      // as well..
291      if (cb::io::maximizeFileDescriptors(limit + 1) != limit) {
292         std::cerr << "FAIL: I expected maximizeFileDescriptors to return "
293                   << "the same max limit" << std::endl;
294         exit(EXIT_FAILURE);
295      }
296   }
297
298   limit = cb::io::maximizeFileDescriptors(std::numeric_limits<uint64_t>::max());
299   if (limit != std::numeric_limits<uint64_t>::max()) {
300      // windows don't have a max limit, and that could be for other platforms
301      // as well..
302      if (cb::io::maximizeFileDescriptors(limit + 1) != limit) {
303         std::cerr << "FAIL: I expected maximizeFileDescriptors to return "
304                   << "the same max limit" << std::endl;
305         exit(EXIT_FAILURE);
306      }
307   }
308}
309
310
311int main(int argc, char **argv)
312{
313   testDirname();
314   testBasename();
315
316   vfs.push_back("fs");
317   vfs.push_back("fs/d1");
318   vfs.push_back("fs/d2");
319   vfs.push_back("fs/e2");
320   vfs.push_back("fs/f2c");
321   vfs.push_back("fs/g2");
322   vfs.push_back("fs/d3");
323   vfs.push_back("fs/1");
324   vfs.push_back("fs/2");
325   vfs.push_back("fs/2c");
326   vfs.push_back("fs/2d");
327   vfs.push_back("fs/3");
328
329   std::list<std::string>::iterator ii;
330   for (ii = vfs.begin(); ii != vfs.end(); ++ii) {
331      if (!CreateDirectory(*ii)) {
332         if (!exists(*ii)) {
333            std::cerr << "Fatal: failed to setup test directory: "
334                      << *ii << std::endl;
335            exit(EXIT_FAILURE);
336         }
337      }
338   }
339
340   testFindFilesWithPrefix();
341   testFindFilesContaining();
342   testRemove();
343
344   testIsDirectory();
345   testIsFile();
346   testMkdirp();
347   testGetCurrentDirectory();
348   testCbMktemp();
349
350   testMaximizeFileDescriptors();
351
352   return exit_value;
353}
354