diff options
Diffstat (limited to 'ACE/tests/Dirent_Test.cpp')
-rw-r--r-- | ACE/tests/Dirent_Test.cpp | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/ACE/tests/Dirent_Test.cpp b/ACE/tests/Dirent_Test.cpp new file mode 100644 index 00000000000..fcff9040409 --- /dev/null +++ b/ACE/tests/Dirent_Test.cpp @@ -0,0 +1,403 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// Dirent_Test.cpp +// +// = DESCRIPTION +// This is a test of the opendir and readdir emulation provided by the +// class ACE_Dirent. It is used to ensure that the emulation code +// works properly on platforms that don't support this capability +// natively. As the emulation code is not compiled in other +// platforms, this test also ensures that there is no impact to +// platforms that natively support directory scanning operations. +// +// = AUTHOR +// Phil Mesnier <mesnier_p@ociweb.com>, +// Zvika Ashani <zvika@aspectusvi.com>, +// Rich Newman <RNewman@directv.com>, and +// Douglas C. Schmidt <d.schmidt@vanderbilt.edu> +// +// ============================================================================ + +#include "test_config.h" +#include "ace/Dirent.h" +#include "ace/Dirent_Selector.h" +#include "ace/OS_NS_sys_stat.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_String.h" +#include "ace/SString.h" + + +ACE_RCSID (tests, + Dirent_Test, + "$Id Dirent_Test.cpp,v 4.10 2003/05/18 19:17:34 dhinton Exp$") + + +#if (defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600)) +# define TEST_DIR "log" +# define DIR_DOT "." +# define DIR_DOT_DOT ".." +# define TEST_ENTRY ".." +#else +# if defined (ACE_LACKS_STRUCT_DIR) || !defined (ACE_HAS_SCANDIR) +# define DIR_DOT ACE_TEXT (".") +# define DIR_DOT_DOT ACE_TEXT ("..") +# define TEST_ENTRY ACE_TEXT ("run_test.lst") +# else +# define DIR_DOT "." +# define DIR_DOT_DOT ".." +# define TEST_ENTRY "run_test.lst" +# endif /* ACE_LACKS_STRUCT_DIR */ +#endif /* ACE_VXWORKS < 0x600 */ + +// Directory to scan - we need to figure it out based on environment. +static ACE_TString TestDir; +static const int RECURSION_INDENT = 3; + +// Number of entries in the directory. +static int entrycount = 0; + +extern "C" { + +static int +selector (const ACE_DIRENT *d) +{ + return ACE_OS::strcmp (d->d_name, TEST_ENTRY) == 0; +} + +static int +comparator (const ACE_DIRENT **d1, const ACE_DIRENT **d2) +{ + return ACE_OS::alphasort (d1, d2); +} + +} /* extern "C" */ + +static int +dirent_selector_test (void) +{ + int status; + int n; + int error = 0; + const ACE_TCHAR *test_dir = TestDir.c_str (); + ACE_Dirent_Selector sds; + + // Pass in functions that'll specify the selection criteria. + status = sds.open (test_dir, selector, comparator); + if (status == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%s, %p\n"), + test_dir, + ACE_TEXT ("open")), + -1); + + // We should only have located ourselves! + if (sds.length () != 1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("selected %d entries in %s, should be 1\n"), + sds.length (), + test_dir)); + error = 1; + } + + for (n = 0; n < sds.length (); ++n) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Sorted: %d: %C\n"), + n, + sds[n]->d_name)); + + status = sds.close (); + if (status == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("after selecting, %p\n"), + ACE_TEXT ("close"))); + error = 1; + } + + ACE_Dirent_Selector ds; + + // Don't specify any selection criteria. + status = ds.open (test_dir); + if (status == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%s w/o selection criteria; %p\n"), + test_dir, + ACE_TEXT ("open"))); + error = 1; + } + + // We counted the entries earlier by hand; should be the same here. + if (entrycount != ds.length ()) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Counted %d entries in %s but selector says %d\n"), + entrycount, + test_dir, + ds.length ())); + error = 1; + } + + for (n = 0; n < ds.length (); ++n) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Entry %d: %C\n"), + n, + ds[n]->d_name)); + + if (ds.close () == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("w/o selection criteria; %p\n"), + ACE_TEXT ("close"))); + error = 1; + } + + return error ? -1 : 0; +} + +static int +dirent_test (void) +{ + ACE_Dirent dir (TestDir.c_str ()); + + for (ACE_DIRENT *directory; + (directory = dir.read ()) != 0; + entrycount++) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Entry %d: %C\n"), + entrycount, + directory->d_name)); + switch (entrycount) + { + case 0: + ACE_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("readdir failed to read anything\n")), -1); + /* NOTREACHED */ + case 1: + ACE_ERROR_RETURN + ((LM_ERROR, + ACE_TEXT ("readdir failed, only matched directory name\n")), + -1); + /* NOTREACHED */ + default: + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("readdir succeeded, read %d entries\n"), + entrycount)); + } + return 0; +} + +static int +dirent_count (const ACE_TCHAR *dir_path, + int &dir_count, + int &file_count, + int recursion_level) +{ +#if !defined (ACE_LACKS_CHDIR) + +# if (defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600)) + // VxWorks only allows full paths (incl. device spec if applicable) to be specified + ACE_TCHAR full_path[MAXPATHLEN]; + if (ACE_OS::getcwd (full_path, sizeof(full_path)) == 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("getcwd: failed\n")), + -1); + if ((ACE_OS::strlen (full_path) + 1 + ACE_OS::strlen (dir_path)) >= sizeof(full_path)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("getcwd: too long\n")), + -1); + ACE_OS::strcat (ACE_OS::strcat (full_path, "/"), dir_path); + if (ACE_OS::chdir (full_path) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("chdir: %p\n"), + full_path), + -1); +# else + if (ACE_OS::chdir (dir_path) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("chdir: %p\n"), + dir_path), + -1); +# endif +#endif /* !ACE_LACKS_CHDIR */ + + ACE_Dirent dir (ACE_TEXT (".")); + + // Since the dir struct d_name type changes depending on the setting + // of ACE_LACKS_STRUCT_DIR, copy each name into a neutral format + // array to work on it. + const size_t maxnamlen = MAXNAMLEN; + ACE_TCHAR tname[maxnamlen + 1]; + + int entry_count = 0; + + for (ACE_DIRENT *directory; (directory = dir.read ()) != 0;) + { + // Skip the ".." and "." files. + if (ACE_OS::strcmp (directory->d_name, DIR_DOT) == 0 + || ACE_OS::strcmp (directory->d_name, DIR_DOT_DOT) == 0) + continue; + ++entry_count; + +#if !defined (ACE_LACKS_STRUCT_DIR) && !defined (__BORLANDC__) + ACE_OS::strncpy (tname, + ACE_TEXT_CHAR_TO_TCHAR (directory->d_name), + maxnamlen); +#else + ACE_OS::strncpy (tname, directory->d_name, maxnamlen); +#endif /* ACE_LACKS_STRUCT_DIR */ + + int local_file_count = 0; + int local_dir_count = 0; + ACE_stat stat_buf; + if (ACE_OS::lstat (directory->d_name, &stat_buf) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + tname), + -1); + + switch (stat_buf.st_mode & S_IFMT) + { + case S_IFREG: // Either a regular file or an executable. + ++file_count; + break; + + case S_IFLNK: // Either a file or directory link, so let's find out. + if (ACE_OS::stat (directory->d_name, &stat_buf) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + tname), + -1); + + if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) + // Don't recurse through symbolic directory links! + ++dir_count; + else + ++file_count; + break; + + case S_IFDIR: + ACE_DEBUG ((LM_DEBUG, "%*sentering subdirectory %s\n", + recursion_level * RECURSION_INDENT, + ACE_TEXT (""), + tname)); + if (dirent_count (tname, + local_dir_count, + local_file_count, + recursion_level + 1) != -1) + { + ACE_DEBUG + ((LM_DEBUG, + ACE_TEXT ("%*ssubdirectory %s has %d files and %d subdirectories.\n"), + recursion_level * RECURSION_INDENT, + ACE_TEXT (""), + tname, + local_file_count, + local_dir_count)); + ++dir_count; + +#if !defined (ACE_LACKS_CHDIR) +# if (defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600)) + // Move back to parent directory. + if (ACE_OS::chdir (full_path) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("chdir: %p\n"), + full_path), + -1); +# else + // Move back up a level. + if (ACE_OS::chdir (ACE_TEXT ("..")) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("chdir: %p\n"), + dir_path), + -1); +# endif +#endif /* !ACE_LACKS_CHDIR */ + } + break; + + default: // Must be some other type of file (PIPE/FIFO/device) + file_count++; + break; + } + } + + return entry_count; +} + +static int +dirent_recurse_test (void) +{ + int total_dirs = 0; + int total_files = 0; + const ACE_TCHAR *test_dir = TestDir.c_str (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Starting directory recursion test for %s\n"), + test_dir)); + + if (dirent_count (test_dir, + total_dirs, + total_files, + 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Directory recursion test failed for %s\n"), + test_dir), + -1); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Directory recursion test succeeded for %s, read %d files %d dirs\n"), + test_dir, + total_files, + total_dirs)); + return 0; +} + +int +run_main (int, ACE_TCHAR *[]) +{ + ACE_START_TEST (ACE_TEXT ("Dirent_Test")); + + // First, find out where to run most of the scans. If a platform has a + // compiled-in setting in TEST_DIR, honor that. Else, look for: + // $top_srcdir/tests: The ACE_wrappers dir for autoconf builds + // $ACE_ROOT/tests: The ACE_wrappers dir for most other builds + // ../test: Last-chance try to hit the right place +#if defined (TEST_DIR) + TestDir = TEST_DIR; +#else + const char *root = ACE_OS::getenv ("top_srcdir"); + if (root == 0) + root = ACE_OS::getenv ("ACE_ROOT"); + if (root != 0) + { + TestDir = ACE_TEXT_CHAR_TO_TCHAR (root); + TestDir += ACE_DIRECTORY_SEPARATOR_STR; + TestDir += ACE_TEXT ("tests"); + } + else + { + TestDir = ACE_TEXT ("../tests"); + } +#endif /* TEST_DIR */ + + int status = 0; + + if (-1 == dirent_test ()) + status = -1; + + if (-1 == dirent_selector_test ()) + status = -1; + + if (-1 == dirent_recurse_test ()) + status = -1; + + ACE_END_TEST; + return status; +} |