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
29using namespace application;
30using namespace basis;
31using namespace mathematics;
32using namespace filesystem;
33using namespace loggers;
34using namespace processes;
35using namespace structures;
36using namespace textual;
37using namespace timely;
38using namespace unit_test;
39
40const 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
48class test_directory_tree : public virtual unit_base, virtual public application_shell
49{
50public:
51 test_directory_tree() : application_shell() {}
52 DEFINE_CLASS_NAME("test_directory_tree");
53 int execute();
54};
55
56int 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/*
69hmmm: this test shows that our algorithms are poor; the tree traversal on feisty meow apex
70should not take as long as it does.
71get some timing around this, comparing it with other linux tools, like ls -R and find.
72see 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.
123 }
124
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;
152LOG(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;
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;
209//LOG(diffs.text_form());
210
211 ASSERT_FALSE(diffs.elements(), "identical directories should stay same after packing");
212
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.
219LOG("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
227LOG("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.
239basis::un_int kid;
240launch_process::run("/bin/rm", astring("-rf ") + tmpdir.raw(), launch_process::AWAIT_APP_EXIT, kid);
241ASSERT_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
259HOOPLE_MAIN(test_directory_tree, )
260
261
The application_shell is a base object for console programs.
virtual int execute()=0
< retrieves the command line from the /proc hierarchy on linux.
application_shell()
constructs an application_shell to serve as the root of the program.
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
static astring get(const astring &variable_name)
looks up the "variable_name" in the current environment variables.
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.
static bool current(dir_tree_iterator &scanning, filename &dir_name, structures::string_array &to_fill)
retrieves the information for the iterator's current location.
static bool compare_trees(const directory_tree &source, const directory_tree &target, filename_list &differences, file_info::file_similarity how_to_compare)
compares the tree in "source" with the tree in "target".
static bool depth(dir_tree_iterator &scanning, int &depth)
returns the current depth of the iterator.
@ prefix
prefix means that subnodes are processed after their parent.
virtual bool unpack(basis::byte_array &packed_form)
unpacks the directory_tree from a byte_array.
static void throw_out(dir_tree_iterator *&to_whack)
cleans up an iterator that was previously opened with start().
static bool next(dir_tree_iterator &scanning)
goes to the next filename in the "scanning" iterator.
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
@ AWAIT_APP_EXIT
stays in the function until the launched application has exited.
static basis::un_int run(const basis::astring &app_name, const basis::astring &command_line, int flag, basis::un_int &child_id)
starts an application using the "app_name" as the executable to run.
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.
static void split_lines(const basis::astring &input, basis::astring &output, int min_column=0, int max_column=79)
formats blocks of text for a maximum width.
static basis::astring indentation(int spaces)
Returns a string made of white space that is "spaces" long.
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
Definition enhance_cpp.h:42
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
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
A platform independent way to obtain the timestamp of a file.
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>
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