feisty meow concerns codebase  2.140
test_filename.cpp
Go to the documentation of this file.
1 /*
2 * Name : test_filename
3 * Author : Chris Koeritz
4 **
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 *
11 */
12 
13 #define DEBUG_FILENAME_TEST
14 
16 #include <basis/functions.h>
17 #include <basis/guards.h>
18 #include <basis/astring.h>
21 #include <loggers/logging_macros.h>
23 #include <filesystem/filename.h>
26 #include <textual/parser_bits.h>
27 #include <unit_test/unit_base.h>
28 
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;
39 
40 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
41 
42 class test_filename : virtual public unit_base, public virtual application_shell
43 {
44 public:
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);
55 };
56 
57 void test_filename::clean_sequel(astring &sequel)
58 { sequel.replace_all('\\', '/'); }
59 
60 astring test_filename::virtual_root()
61 {
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("/");
67  }
68  return virt_root;
69 }
70 
71 void test_filename::dump_string_array(const astring &title, const string_array &to_dump)
72 {
73  FUNCDEF("dump_string_array");
74  LOG(title);
75  for (int i = 0; i < to_dump.length(); i++) {
76  LOG(a_sprintf("%d: '", i) + to_dump[i] + "'");
77  }
78 }
79 
80 /*
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.
88 */
89 
90 bool test_filename::verify_equal_string_array(const astring &group, const string_array &exemplar, const string_array &acolyte)
91 {
92  FUNCDEF("verify_equal_string_array");
93 
94 //temp debug
95 dump_string_array("exemplar", exemplar);
96 dump_string_array("acolyte", acolyte);
97 
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; }
101 
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.
107  }
108  return true;
109 }
110 
111 /*
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).
116 */
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)
120 {
121  FUNCDEF("prepare_string_arrays_for_filenames")
122  bool to_return = true; // success until we learn otherwise.
123 
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);
128 
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);
133  {
134  string_array common_pieces;
135  bool common_rooted;
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;
141  }
142 
143  return to_return;
144 }
145 
146 int test_filename::execute()
147 {
148  FUNCDEF("execute")
149  {
150  // first test group.
151  filename gorgeola("");
152  ASSERT_FALSE(gorgeola.exists(), "an empty filename should not exist");
153  }
154 
155 
156  {
157  // second test group.
158 
159  astring GROUP = "testing separate() ";
160  astring common_bit = "omega/ralph/turkey/buzzard.txt";
161  string_array turkey_pieces;
162  bool turkey_rooted;
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);
167 
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");
170  }
171 
172  {
173  // third test group.
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");
185 
186  astring sequel;
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");
198 
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");
219 
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!");
223  }
224 
225  {
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");
234 
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");
240 
241  ASSERT_FALSE(turkey.compare_suffix(murpin1), GROUP + "compare x.1 failed");
242  }
243 
244  {
245  // fifth test group.
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++) {
252 // log(a_sprintf("parm %d:\n\tfrom \"%s\"\n\t to \"%s\"", i, application::_global_argv[i],
253 // canony.raw().s()), ALWAYS_PRINT);
254 
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
257 // expect.
258 
259  }
260  }
261 
262  {
263  // sixth test group.
264  astring GROUP = "sixth: testing pop and push ";
265  // test dossy paths.
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");
277  test2.pop();
278  test2.pop();
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");
283  test2.pop();
284  ASSERT_EQUAL(test2, filename("c:/"), GROUP + "dpop 3 failed");
285  test2.push("flug");
286  test2.push("blumen");
287  test2.push("klemper");
288  ASSERT_EQUAL(test2, filename("c:/flug/blumen/klemper"), GROUP + "dpush 1 failed");
289  // test unix paths.
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");
298  test4.pop();
299  test4.pop();
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");
304  test4.pop();
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());
309  test4.push("flug");
310  test4.push("blumen");
311  test4.push("klemper");
312  ASSERT_EQUAL(test4, filename(virtual_root() + "flug/blumen/klemper"), GROUP + "upush 1 failed");
313  }
314  {
315  // seventh test group.
316  astring GROUP = "seventh: testing pack and unpack ";
317  filename test1(virtual_root() + "usr/local/athabasca");
318  byte_array packed;
319  int size_guess = test1.packed_size();
320  test1.pack(packed);
321  ASSERT_EQUAL(size_guess, packed.length(), GROUP + "packed_size 1 failed");
322  filename test2;
323  ASSERT_TRUE(test2.unpack(packed), GROUP + "unpack 1 failed");
324  ASSERT_EQUAL(test2, test1, GROUP + "packed contents differ, 1 failed");
325  }
326 #ifdef __WIN32__
327  {
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");
349 
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");
362 
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");
368 
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");
373  }
374 #endif
375 
376  return final_report();
377 }
378 
379 HOOPLE_MAIN(test_filename, )
380 
The application_shell is a base object for console programs.
a_sprintf is a specialization of astring that provides printf style support.
Definition: astring.h:440
int length() const
Returns the current reported length of the allocated C array.
Definition: array.h:115
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
bool t() const
t() is a shortcut for the string being "true", as in non-empty.
Definition: astring.h:97
bool equal_to(const char *that) const
returns true if "that" is equal to this.
Definition: astring.cpp:159
bool replace_all(char to_replace, char new_char)
changes all occurrences of "to_replace" with "new_char".
Definition: astring.cpp:929
int length() const
Returns the current length of the string.
Definition: astring.cpp:132
A very common template for a dynamic array of bytes.
Definition: byte_array.h:36
Provides operations commonly needed on file names.
Definition: filename.h:64
virtual bool unpack(basis::byte_array &packed_form)
Restores the packable from the "packed_form".
Definition: filename.cpp:471
void separate(bool &rooted, structures::string_array &pieces) const
breaks the filename into its component parts.
Definition: filename.cpp:482
void push(const basis::astring &to_push)
pushes a new filename onto the current pathname.
Definition: filename.cpp:152
basis::astring pop()
removes the deepest component of the pathname.
Definition: filename.cpp:138
An array of strings with some additional helpful methods.
Definition: string_array.h:32
bool equal_to(const equalizable &to_compare) const
Compares this string array for equality with "to_compare".
Definition: string_array.h:77
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
Definition: enhance_cpp.h:45
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
Provides macros that implement the 'main' program of an application.
#define HOOPLE_MAIN(obj_name, obj_args)
options that should work for most unix and linux apps.
Definition: hoople_main.h:61
Implements an application lock to ensure only one is running at once.
char ** _global_argv
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
A platform independent way to obtain the timestamp of a file.
Definition: byte_filer.cpp:37
A logger that sends to the console screen using the standard output device.
An extension to floating point primitives providing approximate equality.
Definition: averager.h:21
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
#include <time.h>
Definition: earth_time.cpp:37
Useful support functions for unit testing, especially within hoople.
Definition: unit_base.cpp:35
#define LOG(s)
#define ASSERT_EQUAL(a, b, test_name)
Definition: unit_base.h:38
#define ASSERT_TRUE(a, test_name)
Definition: unit_base.h:46
#define ASSERT_FALSE(a, test_name)
Definition: unit_base.h:50