diff --git a/utils/test-runner.cc b/utils/test-runner.cc index e8bf122d4..840541f82 100644 --- a/utils/test-runner.cc +++ b/utils/test-runner.cc @@ -17,13 +17,146 @@ */ #include "ns3/test.h" +#include "ns3/assert.h" #include #include #include +#include +#include +#include +#include +#include +#include +#include using namespace ns3; +// +// Create a temporary directory for use by test programs. This is not a +// foolproof thing, but a reasonably good way to get a throwaway directory +// while running tests in a debugger. +// +std::string +TempDir (void) +{ + char *path = NULL; + + path = getenv ("TMP"); + if (path == NULL) + { + path = getenv ("TEMP"); + if (path == NULL) + { + path = const_cast ("/tmp"); + } + } + + // + // Just in case the user wants to go back and find the output, we give + // a hint as to which dir we created by including a time hint. + // + time_t now = time (NULL); + struct tm *tm_now = localtime (&now); + + // + // But we also randomize the name in case there are multiple users doing + // this at the same time + // + srandom (time (0)); + long int n = random (); + + // + // The final path to the directory is going to look something like + // + // /tmp/14.30.29.32767 + // + // The first segment comes from one of the temporary directory env + // variables or /tmp if not found. The directory name starts with the + // local time (in this case 14.30.29 -- which is 2:30 and 29 seconds PM). + // + char dirname[1024]; + snprintf (dirname, sizeof(dirname), "%s/%d.%d.%d.%ld", path, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec, n); + + if (mkdir (dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0) + { + return dirname; + } + else + { + return ""; + } +} + +std::string +BaseDir (void) +{ + // + // Get an absolute path to the current working directory. Following code + // depends on the leading '/' + // + char pathbuf[PATH_MAX]; + getcwd (pathbuf, sizeof(pathbuf)); + + // + // Walk up the directory tree looking for a directory that has files that + // indicate it is the base of an ns-3 distribution. We use VERSION and + // LICENSE which have been there from the beginning of time. + // + for (;;) + { + bool haveVersion = false; + bool haveLicense = false; + + // + // Open the directory file for the current directory and loop through + // the directory entries. + // + DIR *dp = opendir (pathbuf); + if (dp != NULL) + { + while (struct dirent *de = readdir (dp)) + { + if (strcmp (de->d_name, "VERSION") == 0) + { + haveVersion = true; + } + + if (strcmp (de->d_name, "LICENSE") == 0) + { + haveLicense = true; + } + } + } + + // + // If there's a file named VERSION and a file named LICENSE in this + // directory, we assume it's our base directory. + // + if (haveVersion && haveLicense) + { + return pathbuf; + } + + // + // Strip off the last segment of the current directory. + // + char *last = strrchr (pathbuf, '/'); + NS_ASSERT_MSG (last, "No \"/\" found in absolute path ???"); + *last = '\0'; + + if (strlen(pathbuf) == 0) + { + return ""; + } + } + + // + // Quiet the compiler. + // + return ""; +} + // // Run one of the test suites. Returns an integer with the boolean sense of // "an error has occurred." That is, 0 == false -> no error; 1 == true -> an @@ -208,19 +341,53 @@ main (int argc, char *argv[]) } // - // If we haven't been asked to run a test suite, we are just going to happily - // try and run everything. Test suites are possibly going to need to figure - // out where there source directory is, and to do that they will need to know - // where the base directory of the distribution is (the directory in which - // "src" is found). We could try and run without it, but when it is needed, - // the test will fail with an assertion. So to be safe, we require a basedir - // to proceed. + // We have a lot of options possible to provide flexibility. It can become + // painful, however, to provide all of the options when debugging, and it + // turns out that not all tests require all options. It is really helpful + // to try and put together some reasonable defaults if we're not provided + // them. // + if (!haveTempdir) + { + // + // No temporary directory was provided. We don't know if the selected + // test or tests will need one, but we can cook something up. The + // tmpnam function has its own set of problems, so we'll just do our + // own thing. + // + tempdir = TempDir (); + if (tempdir.size ()) + { + std::cout << "Temporary directory not provided. Using \"" << tempdir << "\"" << std::endl; + haveTempdir = true; + } + else + { + std::cout << "Temporary directory not provided and unable to create one." << std::endl; + return true; + } + } if (haveBasedir == false) { - std::cout << "Must specify a base directory to run tests (use --basedir option)" << std::endl; - return true; + // + // Test suites are possibly going to need to figure out where their + // source directory is, and to do that they will need to know where + // the base directory of the distribution is (the directory in which + // "src" is found). If we don't have it, we can try and find it in + // the current directory tree. + // + basedir = BaseDir (); + if (basedir.size ()) + { + std::cout << "Base directory not provided. Using \"" << basedir << "\"" << std::endl; + haveBasedir = true; + } + else + { + std::cout << "Base directory not provided and unable to find one." << std::endl; + return true; + } } // @@ -272,6 +439,7 @@ main (int argc, char *argv[]) // if (suiteRan == false) { + std::cout << "Unable to find a test to run (constraints too severe or test not found)" << std::endl; return true; }