3 * Author : Chris Koeritz
5 * Copyright (c) 1993-$now By Author. This program is free software; you can *
6 * redistribute it and/or modify it under the terms of the GNU General Public *
7 * License as published by the Free Software Foundation; either version 2 of *
8 * the License or (at your option) any later version. This is online at: *
9 * http://www.fsf.org/copyleft/gpl.html *
10 * Please send any updates to: fred@gruntose.com *
13 #define DEBUG_FILENAME_TEST
15 #include <application/hoople_main.h>
16 #include <basis/functions.h>
17 #include <basis/guards.h>
18 #include <basis/astring.h>
19 #include <configuration/application_configuration.h>
20 #include <loggers/critical_events.h>
21 #include <loggers/logging_macros.h>
22 #include <loggers/program_wide_logger.h>
23 #include <filesystem/filename.h>
24 #include <structures/static_memory_gremlin.h>
25 #include <structures/string_array.h>
26 #include <textual/parser_bits.h>
27 #include <unit_test/unit_base.h>
29 using namespace application;
30 using namespace basis;
31 using namespace configuration;
32 using namespace mathematics;
33 using namespace filesystem;
34 using namespace loggers;
35 using namespace structures;
36 using namespace textual;
37 using namespace timely;
38 using namespace unit_test;
40 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
42 class test_filename : virtual public unit_base, public virtual application_shell
45 test_filename() : application_shell() {}
46 DEFINE_CLASS_NAME("test_filename");
47 virtual int execute();
48 void clean_sequel(astring &sequel);
49 astring virtual_root();
50 void dump_string_array(const astring &title, const string_array &to_dump);
51 bool verify_equal_string_array(const astring &group, const string_array &exemplar, const string_array &acolyte);
52 bool prepare_string_arrays_for_filenames(const astring &common_bit, const astring &group,
53 bool &exemplar_rooted, string_array &exemplar_pieces, bool &acolyte_rooted,
54 string_array &acolyte_pieces);
57 void test_filename::clean_sequel(astring &sequel)
58 { sequel.replace_all('\\', '/'); }
60 astring test_filename::virtual_root()
62 astring virt_root = application_configuration::virtual_unix_root();
63 if (!!virt_root && !filename::separator(virt_root[virt_root.length() - 1])) {
64 // this is not terminated with a slash, which is possible for dosdows.
65 // we'll make it a reliable directory component by adding a slash.
66 virt_root += astring("/");
71 void test_filename::dump_string_array(const astring &title, const string_array &to_dump)
73 FUNCDEF("dump_string_array");
75 for (int i = 0; i < to_dump.length(); i++) {
76 LOG(a_sprintf("%d: '", i) + to_dump[i] + "'");
81 due to some difference in behavior between the platforms, we need to turn
82 rooted paths that work perfectly find on unix systems into a bizarre messed
83 up c drive version for windows (based on the virtual unix system in place,
84 although only cygwin is currently supported). this assumes the virtual root
85 is available... we accomplish our testing a platform invariant way by by
86 simulating the same operations filename does, but using our exemplar paths
87 as the starting point.
90 bool test_filename::verify_equal_string_array(const astring &group, const string_array &exemplar, const string_array &acolyte)
92 FUNCDEF("verify_equal_string_array");
95 dump_string_array("exemplar", exemplar);
96 dump_string_array("acolyte", acolyte);
98 // doing some extra assertions in here, to complain about what went wrong, but then we still need to return a success value.
99 ASSERT_EQUAL(exemplar.length(), acolyte.length(), group + "the list was the wrong length");
100 if (exemplar.length() != acolyte.length()) { return false; }
102 for (int indy = 0; indy < exemplar.length(); indy++) {
103 bool success = acolyte[indy].equal_to(exemplar[indy]);
104 ASSERT_TRUE(success, group + a_sprintf("piece %d did not match: ", indy) + "'"
105 + acolyte[indy] + "' vs expected '" + exemplar[indy] + "'");
106 if (!success) { return false; } // fail fast.
112 helper method constructs string arrays for the filename with common_bit as
113 the portion after the root ('/'). the exemplar array is generated
114 independently from the acolyte string array to ensure that it is correctly
115 constructed (with a virtual root and then a non-rooted chunk).
117 bool test_filename::prepare_string_arrays_for_filenames(const astring &common_bit, const astring &group,
118 bool &exemplar_rooted, string_array &exemplar_pieces,
119 bool &acolyte_rooted, string_array &acolyte_pieces)
121 FUNCDEF("prepare_string_arrays_for_filenames")
122 bool to_return = true; // success until we learn otherwise.
124 // generate the acolyte, which will be tested again, very straightforwardly.
125 // it is a non-rooted string, so we just slap the virtual root in front.
126 filename acolyte_fn(virtual_root() + common_bit);
127 acolyte_fn.separate(acolyte_rooted, acolyte_pieces);
129 // generate the exemplar without allowing filename to operate on the whole
130 // string. we get the virtual root first and operate on it as a filename,
131 // then we slap on the unrooted portion to get the unmanipulated form.
132 filename(virtual_root()).separate(exemplar_rooted, exemplar_pieces);
134 string_array common_pieces;
136 filename(common_bit).separate(common_rooted, common_pieces);
137 ASSERT_FALSE(common_rooted, group + "the common_rooted value is erreonous");
138 if (common_rooted) { to_return = false; }
139 // conjoin the rooty pieces with the common bits, hopefully hitting both platforms' sweet spots.
140 exemplar_pieces += common_pieces;
146 int test_filename::execute()
151 filename gorgeola("");
152 ASSERT_FALSE(gorgeola.exists(), "an empty filename should not exist");
157 // second test group.
159 astring GROUP = "testing separate() ";
160 astring common_bit = "omega/ralph/turkey/buzzard.txt";
161 string_array turkey_pieces;
163 string_array exemplar_pieces;
164 bool exemplar_rooted;
165 bool worked = test_filename::prepare_string_arrays_for_filenames(common_bit, GROUP,
166 exemplar_rooted, exemplar_pieces, turkey_rooted, turkey_pieces);
168 ASSERT_EQUAL(turkey_rooted, exemplar_rooted, GROUP + "the turkey_rooted value is erreonous.");
169 ASSERT_TRUE(verify_equal_string_array(GROUP, exemplar_pieces, turkey_pieces), "the turkey array differs from exemplar");
174 astring GROUP = "third: test compare_prefix ";
175 filename turkey(virtual_root() + "omega/ralph/turkey/buzzard.txt");
176 filename murpin1(virtual_root() + "omega");
177 filename murpin2(virtual_root() + "omega/ralph");
178 filename murpin3(virtual_root() + "omega/ralph/turkey");
179 filename murpin4(virtual_root() + "omega/ralph/turkey/buzzard.txt");
180 filename murpin_x1("ralph/turkey/buzzard.txt");
181 filename murpin_x2(virtual_root() + "omega/ralph/turkey/buzzard.txt2");
182 filename murpin_x3(virtual_root() + "omega/turkey/buzzard.txt");
183 filename murpin_x4(virtual_root() + "omega/ralph/turkey/b0/buzzard.txt");
184 filename murpin_x5("moomega/ralph/turkey");
187 ASSERT_TRUE(murpin1.compare_prefix(turkey, sequel), GROUP + "first should match but didn't");
188 clean_sequel(sequel);
189 ASSERT_TRUE(sequel.equal_to("ralph/turkey/buzzard.txt"), GROUP + "first sequel was wrong");
190 ASSERT_TRUE(murpin2.compare_prefix(turkey, sequel), GROUP + "second should match but didn't");
191 clean_sequel(sequel);
192 ASSERT_TRUE(sequel.equal_to("turkey/buzzard.txt"), GROUP + "second sequel was wrong");
193 ASSERT_TRUE(murpin3.compare_prefix(turkey, sequel), GROUP + "third should match but didn't");
194 clean_sequel(sequel);
195 ASSERT_TRUE(sequel.equal_to("buzzard.txt"), GROUP + "third sequel was wrong");
196 ASSERT_TRUE(murpin4.compare_prefix(turkey, sequel), GROUP + "fourth should match but didn't");
197 ASSERT_FALSE(sequel.t(), GROUP + "fourth had a sequel but shouldn't");
199 ASSERT_FALSE(murpin_x1.compare_prefix(turkey, sequel),
200 GROUP + "x-first should not match but did");
201 ASSERT_FALSE(sequel.t(),
202 GROUP + "x-first had a sequel but shouldn't");
203 ASSERT_FALSE(murpin_x2.compare_prefix(turkey, sequel),
204 GROUP + "x-second should not match but did");
205 ASSERT_FALSE(sequel.t(),
206 GROUP + "x-second had a sequel but shouldn't");
207 ASSERT_FALSE(murpin_x3.compare_prefix(turkey, sequel),
208 GROUP + "x-third should not match but did");
209 ASSERT_FALSE(sequel.t(),
210 GROUP + "x-third had a sequel but shouldn't");
211 ASSERT_FALSE(murpin_x4.compare_prefix(turkey, sequel),
212 GROUP + "x-fourth should not match but did");
213 ASSERT_FALSE(sequel.t(),
214 GROUP + "x-fourth had a sequel but shouldn't");
215 ASSERT_FALSE(murpin_x5.compare_prefix(turkey, sequel),
216 GROUP + "x-fifth should not match but did");
217 ASSERT_FALSE(sequel.t(),
218 GROUP + "x-fifth had a sequel but shouldn't");
220 // check that the functions returning no sequel are still correct.
221 ASSERT_TRUE(murpin1.compare_prefix(turkey), GROUP + "the two versions differed!");
222 ASSERT_FALSE(murpin_x1.compare_prefix(turkey), GROUP + "x-the two versions differed!");
226 // fourth test group.
227 astring GROUP = "fourth: test compare_suffix ";
228 filename turkey(virtual_root() + "omega/ralph/turkey/buzzard.txt");
229 filename murpin1("turkey\\buzzard.txt");
230 filename murpin2("turkey/buzzard.txt");
231 filename murpin3("ralph/turkey/buzzard.txt");
232 filename murpin4("omega/ralph/turkey/buzzard.txt");
233 filename murpin5(virtual_root() + "omega/ralph/turkey/buzzard.txt");
235 ASSERT_TRUE(murpin1.compare_suffix(turkey), GROUP + "compare 1 failed");
236 ASSERT_TRUE(murpin2.compare_suffix(turkey), GROUP + "compare 2 failed");
237 ASSERT_TRUE(murpin3.compare_suffix(turkey), GROUP + "compare 3 failed");
238 ASSERT_TRUE(murpin4.compare_suffix(turkey), GROUP + "compare 4 failed");
239 ASSERT_TRUE(murpin5.compare_suffix(turkey), GROUP + "compare 5 failed");
241 ASSERT_FALSE(turkey.compare_suffix(murpin1), GROUP + "compare x.1 failed");
246 // tests out the canonicalization method on any parameters given on
247 // the command line, including the program name.
248 astring GROUP = "fifth: canonicalize command-line paths ";
249 // log(GROUP, ALWAYS_PRINT);
250 for (int i = 0; i < application::_global_argc; i++) {
251 filename canony(application::_global_argv[i]);
252 // log(a_sprintf("parm %d:\n\tfrom \"%s\"\n\t to \"%s\"", i, application::_global_argv[i],
253 // canony.raw().s()), ALWAYS_PRINT);
255 //hmmm: the above wasn't really a test so much as a look at what we did.
256 // we should run the canonicalizer against a set of known paths so we can know what to
264 astring GROUP = "sixth: testing pop and push ";
266 filename test1("c:/flug/blumen/klemper/smooden");
267 //log(astring("base=") + test1.basename(), ALWAYS_PRINT);
268 ASSERT_EQUAL(test1.basename(), astring("smooden"), GROUP + "basename 1 failed");
269 //log(astring("got past basename 1 test that was failing."));
270 ASSERT_EQUAL(test1.dirname(), filename("c:/flug/blumen/klemper"),
271 GROUP + "d-dirname 1 failed");
272 //log(astring("got past a test or so after that."));
273 filename test2 = test1;
274 astring popped = test2.pop();
275 ASSERT_EQUAL(popped, astring("smooden"), GROUP + "dpop 1 return failed");
276 ASSERT_EQUAL(test2, filename("c:/flug/blumen/klemper"), GROUP + "dpop 1 failed");
279 ASSERT_EQUAL(test2, filename("c:/flug"), GROUP + "dpop 2 failed");
280 popped = test2.pop();
281 ASSERT_EQUAL(popped, astring("flug"), GROUP + "dpop 1 return failed");
282 ASSERT_EQUAL(test2, filename("c:/"), GROUP + "dpop 3 failed");
284 ASSERT_EQUAL(test2, filename("c:/"), GROUP + "dpop 3 failed");
286 test2.push("blumen");
287 test2.push("klemper");
288 ASSERT_EQUAL(test2, filename("c:/flug/blumen/klemper"), GROUP + "dpush 1 failed");
290 filename test3(virtual_root() + "flug/blumen/klemper/smooden");
291 ASSERT_EQUAL(test3.basename(), astring("smooden"), GROUP + "basename 1 failed");
292 ASSERT_EQUAL(test3.dirname(), filename(virtual_root() + "flug/blumen/klemper"),
293 GROUP + "u-dirname 1 failed");
294 filename test4 = test3;
295 popped = test4.pop();
296 ASSERT_EQUAL(popped, astring("smooden"), GROUP + "upop 1 return failed");
297 ASSERT_EQUAL(test4, filename(virtual_root() + "flug/blumen/klemper"), GROUP + "upop 1 failed");
300 ASSERT_EQUAL(test4, filename(virtual_root() + "flug"), GROUP + "upop 2 failed");
301 popped = test4.pop();
302 ASSERT_EQUAL(popped, astring("flug"), GROUP + "upop 2 return failed");
303 ASSERT_EQUAL(test4, filename(virtual_root()), GROUP + "upop 3 failed");
305 filename special_popped = filename(virtual_root());
306 special_popped.pop();
307 ASSERT_EQUAL(test4, special_popped, GROUP + "upop 4 failed");
308 test4 = filename(virtual_root());
310 test4.push("blumen");
311 test4.push("klemper");
312 ASSERT_EQUAL(test4, filename(virtual_root() + "flug/blumen/klemper"), GROUP + "upush 1 failed");
315 // seventh test group.
316 astring GROUP = "seventh: testing pack and unpack ";
317 filename test1(virtual_root() + "usr/local/athabasca");
319 int size_guess = test1.packed_size();
321 ASSERT_EQUAL(size_guess, packed.length(), GROUP + "packed_size 1 failed");
323 ASSERT_TRUE(test2.unpack(packed), GROUP + "unpack 1 failed");
324 ASSERT_EQUAL(test2, test1, GROUP + "packed contents differ, 1 failed");
328 // eighth test group is only for windows side.
329 astring GROUP = "eighth: cygwin and msys paths ";
330 filename test1("/cygdrive/q/marbles");
331 ASSERT_EQUAL(test1, astring("q:/marbles"), GROUP + "test 1 failed");
332 filename test2("/cygdrive/r");
333 ASSERT_EQUAL(test2, astring("r:/"), GROUP + "test 2 failed");
334 filename test3("/cygdrive/r/");
335 ASSERT_EQUAL(test3, astring("r:/"), GROUP + "test 3 failed");
336 // this is a broken pattern, which we don't expect to resolve to a drive.
337 filename test4("/cygdrive//");
338 ASSERT_EQUAL(test4, virtual_root() + "cygdrive", GROUP + "test 4 failed");
339 // another broken pattern.
340 filename test5("/cygdrive/");
341 ASSERT_EQUAL(test5, virtual_root() + "cygdrive", GROUP + "test 5 failed");
342 // and one more. not great tests, but whatever.
343 filename test6("/cygdrive");
344 ASSERT_EQUAL(test6, virtual_root() + "cygdrive", GROUP + "test 6 failed");
345 filename test7(virtual_root() + "klaunspendle");
346 ASSERT_EQUAL(test7, astring(virtual_root() + "klaunspendle"), GROUP + "test 7 failed");
347 filename test8("z:/klaunspendle");
348 ASSERT_EQUAL(test8, astring("z:/klaunspendle"), GROUP + "test 8 failed");
350 filename test10("/q/borkage");
351 ASSERT_EQUAL(test10, astring("q:/borkage"), GROUP + "test 10 failed");
352 filename test11("/q/r");
353 ASSERT_EQUAL(test11, astring("q:/r"), GROUP + "test 11 failed");
354 filename test12("/q/r/");
355 ASSERT_EQUAL(test12, astring("q:/r"), GROUP + "test 12 failed");
356 filename test13("/q/r/x");
357 ASSERT_EQUAL(test13, astring("q:/r/x"), GROUP + "test 13 failed");
358 filename test14("/r/");
359 ASSERT_EQUAL(test14, astring("r:/"), GROUP + "test 14 failed");
360 filename test15("/r");
361 ASSERT_EQUAL(test15, astring("r:/"), GROUP + "test 15 failed");
363 bool ex_rooted, ac_rooted;
364 string_array exemplar, acolyte;
365 ASSERT_TRUE(prepare_string_arrays_for_filenames(astring(""), GROUP,
366 ex_rooted, exemplar, ac_rooted, acolyte), GROUP + "test 16 failed prep");
367 ASSERT_TRUE(verify_equal_string_array(GROUP, exemplar, acolyte), GROUP + "test 16 failed compare");
369 filename test17("r/");
370 ASSERT_EQUAL(test17, astring("r/"), GROUP + "test 17 failed");
371 filename test18(virtual_root() + "kr/soop");
372 ASSERT_EQUAL(test18, astring(virtual_root() + "kr/soop"), GROUP + "test 18 failed");
376 return final_report();
379 HOOPLE_MAIN(test_filename, )