feisty meow concerns codebase  2.140
test_directory_tree.cpp
Go to the documentation of this file.
1 /*
2 * Name : test_directory_tree
3 * Author : Chris Koeritz
4 * Purpose:
5 * Tests the directory_tree object on some well-known directories.
6 **
7 * Copyright (c) 2001-$now By Author. This program is free software; you can
8 * redistribute it and/or modify it under the terms of the GNU General Public
9 * License as published by the Free Software Foundation; either version 2 of
10 * the License or (at your option) any later version. This is online at:
11 * http://www.fsf.org/copyleft/gpl.html
12 * Please send any updates to: fred@gruntose.com
13 */
14 
16 #include <basis/functions.h>
17 #include <basis/guards.h>
19 #include <filesystem/filename.h>
27 #include <unit_test/unit_base.h>
28 
29 using namespace application;
30 using namespace basis;
31 using namespace mathematics;
32 using namespace filesystem;
33 using namespace loggers;
34 using namespace processes;
35 using namespace structures;
36 using namespace textual;
37 using namespace timely;
38 using namespace unit_test;
39 
40 const bool JUST_SIZES = false;
41  // determines if we'll only compare file size and time.
42 
43 #define DEBUG_TEST_DIRECTORY_TREE
44  // uncomment if you want noisy logging.
45 
46 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
47 
48 class test_directory_tree : public virtual unit_base, virtual public application_shell
49 {
50 public:
51  test_directory_tree() : application_shell() {}
52  DEFINE_CLASS_NAME("test_directory_tree");
53  int execute();
54 };
55 
56 int test_directory_tree::execute()
57 {
58  FUNCDEF("execute");
59 
60 /* old approach.
61  astring path = "/usr/lib";
62 #ifdef __WIN32__
63  // default path for windoze uses an area that should always exist.
64  path = environment::get("COMMONPROGRAMFILES");
65 #endif
66 */
67 
68 /*
69 hmmm: this test shows that our algorithms are poor; the tree traversal on feisty meow apex
70 should not take as long as it does.
71 get some timing around this, comparing it with other linux tools, like ls -R and find.
72 see if we have some ugly bottlenecks, or where they are, and fix them.
73 */
74 
75  // new approach for where to look is at feisty meow itself.
76  // some type of introspection to be sure.
77  astring path = environment::get("FEISTY_MEOW_APEX");
78 
79  // process the command line parameters, which are optionally a directory name and
80  // a pattern to use when scanning.
81  if (_global_argc >= 2)
82  path = _global_argv[1];
83 
84  astring pattern = "*";
85  if (_global_argc >= 3)
86  pattern = _global_argv[2];
87 
88  {
89 #ifdef DEBUG_TEST_DIRECTORY_TREE
90  log(astring("Scanning directory tree at \"") + path + "\"");
91  log(astring("Using pattern-match \"") + pattern + "\"");
92 #endif
93 
94  directory_tree dir(path, pattern.s());
95  ASSERT_TRUE(dir.good(), "directory_tree construction should succeed and be readable.");
96 
97  dir_tree_iterator *ted = dir.start(directory_tree::prefix);
98  // create our iterator to do a prefix traversal.
99 
100  int depth; // current depth in tree.
101  filename curr; // the current path the iterator is at.
102  string_array files; // the filenames held at the iterator.
103 
104  while (directory_tree::current(*ted, curr, files)) {
105  // we have a good directory to show.
106  directory_tree::depth(*ted, depth);
107 #ifdef DEBUG_TEST_DIRECTORY_TREE
108  log(string_manipulation::indentation(depth * 2) + astring("[") + curr.raw() + "]");
109 #endif
110 
111  astring names;
112  for (int i = 0; i < files.length(); i++) names += files[i] + " ";
113  if (names.length()) {
114  astring split;
115  string_manipulation::split_lines(names, split, depth * 2 + 2);
116 #ifdef DEBUG_TEST_DIRECTORY_TREE
117  log(split);
118 #endif
119  }
120 
121  // go to the next place.
122  directory_tree::next(*ted);
123  }
124 
125  directory_tree::throw_out(ted);
126  }
127 
128  {
129  // second test group. seek operation.
130 //scan the directory, create some temporary directories and junk filenames
131 //therein, then seek to that location.
132 
133  }
134 
135  {
136  // third test group. tree comparison operation.
137 // log(astring("Self-comparing directory tree at \"") + path + "\"");
138 // log(astring("Using pattern-match \"") + pattern + "\"");
139 
140 // LOG("reading tree 1.");
141  directory_tree dir(path, pattern.s());
142  ASSERT_TRUE(dir.good(), "the directory should be readable for self-compare");
143 
144  // now read a copy of the tree also.
145 // LOG("reading tree 2.");
146  directory_tree dir2(path, pattern.s());
147  ASSERT_TRUE(dir2.good(), "the directory should read the second time fine too");
148 
149  LOG("comparing the two trees.");
150  filename_list diffs;
151  directory_tree::compare_trees(dir, dir2, diffs, file_info::EQUAL_CHECKSUM_TIMESTAMP_FILESIZE);
152 LOG(diffs.text_form());
153 
154  ASSERT_FALSE(diffs.elements(), "there should be no differences comparing identical dirs");
155  }
156 
157  {
158  // fourth test: see if the calculate function works.
159 // log(astring("Calculating sums for tree at \"") + path + "\"");
160 // log(astring("Using pattern-match \"") + pattern + "\"");
161 
162 // LOG("reading tree 1.");
163  directory_tree dir(path, pattern.s());
164  ASSERT_TRUE(dir.good(), "the directory should be readable for checksums");
165 
166  // now read a copy of the tree also.
167 // LOG("reading tree 2.");
168  directory_tree dir2(path, pattern.s());
169  ASSERT_TRUE(dir2.good(), "checksummer should be able to read second time also");
170 
171 // LOG("calculating checksums for tree 1.");
172  ASSERT_TRUE(dir.calculate(JUST_SIZES), "the first checksummer tree can be calculated");
173 
174 // LOG("calculating checksums for tree 2.");
175  ASSERT_TRUE(dir2.calculate(JUST_SIZES), "the second checksummer tree can be calculated");
176 
177 // LOG("comparing the two trees.");
178  filename_list diffs;
179  directory_tree::compare_trees(dir, dir2, diffs, file_info::EQUAL_CHECKSUM_TIMESTAMP_FILESIZE);
180 //LOG(diffs.text_form());
181 
182  ASSERT_FALSE(diffs.elements(), "no checksummer differences should be seen for identical directories");
183  }
184 
185  {
186  // fifth test: see if the packing works.
187 // log(astring("Reading tree for packing at \"") + path + "\"");
188 // log(astring("Using pattern-match \"") + pattern + "\"");
189 
190 // LOG("reading tree.");
191  directory_tree dir(path, pattern.s());
192  ASSERT_TRUE(dir.good(), "packer directory should be read");
193 
194 // LOG("calculating checksums for tree.");
195  ASSERT_TRUE(dir.calculate(JUST_SIZES), "the first packer tree can be calculated");
196 
197  byte_array packed_form;
198  int size_packed = dir.packed_size();
199  dir.pack(packed_form);
200 //LOG(a_sprintf("tree became %d abyte array", packed_form.length()));
201  ASSERT_EQUAL(size_packed, packed_form.length(), "packed size should be right");
202 
203  directory_tree dir2;
204  ASSERT_TRUE(dir2.unpack(packed_form), "second tree can be unpacked from the first");
205 
206 // LOG("comparing the two trees.");
207  filename_list diffs;
208  directory_tree::compare_trees(dir, dir2, diffs, file_info::EQUAL_CHECKSUM_TIMESTAMP_FILESIZE);
209 //LOG(diffs.text_form());
210 
211  ASSERT_FALSE(diffs.elements(), "identical directories should stay same after packing");
212 
213  directory_tree::compare_trees(dir2, dir, diffs, file_info::EQUAL_CHECKSUM_TIMESTAMP_FILESIZE);
214  ASSERT_FALSE(diffs.elements(), "no differences for reverse compare identical dirs");
215  }
216 
217  {
218  // sixth test: see if the make_directories function works.
219 LOG("reading tree to recreate");
220  directory_tree dir(path, pattern.s());
221  ASSERT_TRUE(dir.good(), "makedirs test directory reading");
222  filename tmpdir(environment::get("FEISTY_MEOW_GENERATED_STORE") + "/zz_balfazzaral");
223  LOG(astring("will write to tmp in ") + tmpdir);
224  basis::outcome result = dir.make_directories(tmpdir.raw());
225  ASSERT_EQUAL(result.value(), common::OKAY, "makedirs should succeed");
226 
227 LOG("what happened with that? did it work? merely rhetorical, since we need more code here.");
228 
229 //hmmm: compare the directories with what we expect to be made;
230 // do a dirtree iterator on the path, and make sure each of those exists in the target place.
231 
232 
233  // clean up the output directory.
234 //this won't do it; it's a directory!
235 // bool worked = tmpdir.recursive_unlink();
236 // ASSERT_TRUE(worked, "removing temporary files after test");
237 
238 //hmmm: plug in real recursive delete here instead.
239 basis::un_int kid;
240 launch_process::run("/bin/rm", astring("-rf ") + tmpdir.raw(), launch_process::AWAIT_APP_EXIT, kid);
241 ASSERT_FALSE(kid, "removing temporary files after test");
242 
243  }
244 
245 
246 // nth test:
247 // combine the results of the second test with a comparison like in the
248 // third test. delete all of those temporary files that were added.
249 // rescan tree. make sure that a tree containing the temporaries
250 // when compared with the current post-deletion tree produces a list
251 // that contains all the temporary files and directories.
252 
253 
254 //hmmm: more tests!
255 
256  return final_report();
257 }
258 
259 HOOPLE_MAIN(test_directory_tree, )
260 
261 
The application_shell is a base object for console programs.
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
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition: astring.h:113
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
Outcomes describe the state of completion for an operation.
Definition: outcome.h:31
int value() const
Definition: outcome.h:51
An object that traverses directory trees and provides a view of all files.
virtual bool unpack(basis::byte_array &packed_form)
unpacks the directory_tree from a byte_array.
basis::astring text_form(int max_lines=MAXINT32) const
max_lines is the maximum number of lines to print into the string.
Provides operations commonly needed on file names.
Definition: filename.h:64
const basis::astring & raw() const
returns the astring that we're holding onto for the path.
Definition: filename.cpp:97
int elements() const
the maximum number of elements currently allowed in this amorph.
Definition: amorph.h:66
An array of strings with some additional helpful methods.
Definition: string_array.h:32
#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
unsigned int un_int
Abbreviated name for unsigned integers.
Definition: definitions.h:62
list files
Definition: eml_to_txt.py:157
string path
Definition: eml_to_txt.py:139
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
None split_lines(str unsplit_line)
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
const bool JUST_SIZES
#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