1#include <iostream>
2#include <platform/dirutils.h>
3#include <cstdlib>
4#include <list>
5#include <string>
6#include <cerrno>
7#include <cstring>
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <stdio.h>
11
12#ifdef WIN32
13#include <windows.h>
14#include <direct.h>
15static bool CreateDirectory(const std::string &dir) {
16    if (_mkdir(dir.c_str()) != 0) {
17        return false;
18    }
19    return true;
20}
21
22#define PATH_SEPARATOR "\\"
23
24#else
25static bool CreateDirectory(const std::string &dir) {
26   if (mkdir(dir.c_str(), S_IXUSR | S_IWUSR | S_IRUSR) != 0) {
27      return false;
28   }
29   return true;
30}
31
32#define PATH_SEPARATOR "/"
33
34#endif
35
36#undef NDEBUG
37#include <cassert>
38
39int exit_value = EXIT_SUCCESS;
40
41static void expect(const std::string &exp, const std::string &val) {
42   if (exp != val) {
43      std::cerr << "Expected " << exp << " got [" << val << "]" << std::endl;
44      exit_value = EXIT_FAILURE;
45   }
46}
47
48static void expect(size_t size, const std::vector<std::string> &vec) {
49   if (vec.size() != size) {
50      std::cerr << "Expected vector of " << size
51                << " elements got [" << vec.size() << "]" << std::endl;
52      exit_value = EXIT_FAILURE;
53   }
54}
55
56static void contains(const std::string &val, const std::vector<std::string> &vec) {
57   std::vector<std::string>::const_iterator ii;
58   for (ii = vec.begin(); ii != vec.end(); ++ii) {
59      if (val == *ii) {
60         return ;
61      }
62   }
63
64   std::cerr << "Expected vector to contain [" << val << "]" << std::endl;
65   for (ii = vec.begin(); ii != vec.end(); ++ii) {
66      std::cerr << "  -> " << *ii << std::endl;
67   }
68   std::cerr << std::endl;
69   exit_value = EXIT_FAILURE;
70}
71
72static std::list<std::string> vfs;
73
74static bool exists(const std::string &path) {
75   struct stat st;
76   return stat(path.c_str(), &st) == 0;
77}
78
79static void testDirname(void) {
80   // Check the simple case
81   expect("foo", CouchbaseDirectoryUtilities::dirname("foo\\bar"));
82   expect("foo", CouchbaseDirectoryUtilities::dirname("foo/bar"));
83
84   // Make sure that we remove double an empty chunk
85   expect("foo", CouchbaseDirectoryUtilities::dirname("foo\\\\bar"));
86   expect("foo", CouchbaseDirectoryUtilities::dirname("foo//bar"));
87
88   // Make sure that we handle the case without a directory
89   expect(".", CouchbaseDirectoryUtilities::dirname("bar"));
90   expect(".", CouchbaseDirectoryUtilities::dirname(""));
91
92   // Absolute directories
93   expect("\\", CouchbaseDirectoryUtilities::dirname("\\bar"));
94   expect("\\", CouchbaseDirectoryUtilities::dirname("\\\\bar"));
95   expect("/", CouchbaseDirectoryUtilities::dirname("/bar"));
96   expect("/", CouchbaseDirectoryUtilities::dirname("//bar"));
97
98   // Test that we work with multiple directories
99   expect("1/2/3/4/5", CouchbaseDirectoryUtilities::dirname("1/2/3/4/5/6"));
100   expect("1\\2\\3\\4\\5", CouchbaseDirectoryUtilities::dirname("1\\2\\3\\4\\5\\6"));
101   expect("1/2\\4/5", CouchbaseDirectoryUtilities::dirname("1/2\\4/5\\6"));
102}
103
104static void testBasename(void) {
105   expect("bar", CouchbaseDirectoryUtilities::basename("foo\\bar"));
106   expect("bar", CouchbaseDirectoryUtilities::basename("foo/bar"));
107   expect("bar", CouchbaseDirectoryUtilities::basename("foo\\\\bar"));
108   expect("bar", CouchbaseDirectoryUtilities::basename("foo//bar"));
109   expect("bar", CouchbaseDirectoryUtilities::basename("bar"));
110   expect("", CouchbaseDirectoryUtilities::basename(""));
111   expect("bar", CouchbaseDirectoryUtilities::basename("\\bar"));
112   expect("bar", CouchbaseDirectoryUtilities::basename("\\\\bar"));
113   expect("bar", CouchbaseDirectoryUtilities::basename("/bar"));
114   expect("bar", CouchbaseDirectoryUtilities::basename("//bar"));
115   expect("6", CouchbaseDirectoryUtilities::basename("1/2/3/4/5/6"));
116   expect("6", CouchbaseDirectoryUtilities::basename("1\\2\\3\\4\\5\\6"));
117   expect("6", CouchbaseDirectoryUtilities::basename("1/2\\4/5\\6"));
118}
119
120static void testFindFilesWithPrefix(void) {
121   using namespace CouchbaseDirectoryUtilities;
122
123   std::vector<std::string> vec = findFilesWithPrefix("fs");
124   expect(1, vec);
125   contains("." PATH_SEPARATOR "fs", vec);
126
127   vec = findFilesWithPrefix("fs", "d");
128   expect(3, vec);
129   contains("fs" PATH_SEPARATOR "d1", vec);
130   contains("fs" PATH_SEPARATOR "d2", vec);
131   contains("fs" PATH_SEPARATOR "d3", vec);
132   vec = findFilesWithPrefix("fs", "1");
133   expect(1, vec);
134   contains("fs" PATH_SEPARATOR "1", vec);
135
136   vec = findFilesWithPrefix("fs", "");
137   expect(vfs.size() - 1, vec);
138
139}
140
141static void testFindFilesContaining(void) {
142   using namespace CouchbaseDirectoryUtilities;
143   std::vector<std::string> vec = findFilesContaining("fs", "");
144   expect(vfs.size() - 1, vec);
145
146   vec = findFilesContaining("fs", "2");
147   expect(7, vec);
148   contains("fs" PATH_SEPARATOR "d2", vec);
149   contains("fs" PATH_SEPARATOR "e2", vec);
150   contains("fs" PATH_SEPARATOR "f2c", vec);
151   contains("fs" PATH_SEPARATOR "g2", vec);
152   contains("fs" PATH_SEPARATOR "2", vec);
153   contains("fs" PATH_SEPARATOR "2c", vec);
154   contains("fs" PATH_SEPARATOR "2d", vec);
155}
156
157static void testRemove(void) {
158   fclose(fopen("test-file", "w"));
159   if (!CouchbaseDirectoryUtilities::rmrf("test-file")) {
160      std::cerr << "expected to delete existing file" << std::endl;
161   }
162   if (CouchbaseDirectoryUtilities::rmrf("test-file")) {
163      std::cerr << "Didn't expected to delete non-existing file" << std::endl;
164   }
165
166   if (!CouchbaseDirectoryUtilities::rmrf("fs")) {
167      std::cerr << "Expected to nuke the entire fs directory recursively" << std::endl;
168   }
169}
170
171int main(int argc, char **argv)
172{
173   testDirname();
174   testBasename();
175
176
177   vfs.push_back("fs");
178   vfs.push_back("fs/d1");
179   vfs.push_back("fs/d2");
180   vfs.push_back("fs/e2");
181   vfs.push_back("fs/f2c");
182   vfs.push_back("fs/g2");
183   vfs.push_back("fs/d3");
184   vfs.push_back("fs/1");
185   vfs.push_back("fs/2");
186   vfs.push_back("fs/2c");
187   vfs.push_back("fs/2d");
188   vfs.push_back("fs/3");
189
190   std::list<std::string>::iterator ii;
191   for (ii = vfs.begin(); ii != vfs.end(); ++ii) {
192      if (!CreateDirectory(*ii)) {
193         if (!exists(*ii)) {
194            std::cerr << "Fatal: failed to setup test directory: "
195                      << *ii << std::endl;
196            exit(EXIT_FAILURE);
197         }
198      }
199   }
200
201   testFindFilesWithPrefix();
202   testFindFilesContaining();
203   testRemove();
204
205   return exit_value;
206}
207