# Fixed Linux execution problem. Extended unit-test system.
Fix sys_get_executable_name. Add mock object support. Add CxxTest wrapper to support "-test TestSuitename" and "-test TestSuitename::test_case_name" command-line arguments for running individual tests. This was SVN commit r7081.
This commit is contained in:
parent
58ee7038db
commit
6374080b60
@ -334,7 +334,9 @@ function setup_static_lib_package (package_name, rel_source_dirs, extern_libs, e
|
||||
package_add_contents(source_root, rel_source_dirs, {}, extra_params)
|
||||
package_add_extern_libs(extern_libs)
|
||||
|
||||
tinsert(static_lib_names, package_name)
|
||||
if not extra_params["no_default_link"] then
|
||||
tinsert(static_lib_names, package_name)
|
||||
end
|
||||
|
||||
if OS == "windows" then
|
||||
tinsert(package.buildflags, "no-rtti")
|
||||
@ -353,8 +355,10 @@ function setup_static_lib_package (package_name, rel_source_dirs, extern_libs, e
|
||||
-- correctly open these files from the IDE.
|
||||
-- * precompiled.cpp (needed to "Create" the PCH) also goes in
|
||||
-- the abovementioned dir.
|
||||
pch_dir = source_root.."pch/"..package_name.."/"
|
||||
package_setup_pch(pch_dir, "precompiled.h", "precompiled.cpp")
|
||||
if not extra_params["no_default_pch"] then
|
||||
pch_dir = source_root.."pch/"..package_name.."/"
|
||||
package_setup_pch(pch_dir, "precompiled.h", "precompiled.cpp")
|
||||
end
|
||||
end
|
||||
|
||||
-- this is where the source tree is chopped up into static libs.
|
||||
@ -486,7 +490,8 @@ function setup_all_libs ()
|
||||
"vorbis",
|
||||
"libjpg",
|
||||
"cryptopp",
|
||||
"valgrind"
|
||||
"valgrind",
|
||||
"cxxtest",
|
||||
}
|
||||
|
||||
-- CPU architecture-specific
|
||||
@ -518,6 +523,18 @@ function setup_all_libs ()
|
||||
end
|
||||
|
||||
setup_static_lib_package("lowlevel", source_dirs, extern_libs, {})
|
||||
|
||||
|
||||
-- CxxTest mock function support
|
||||
extern_libs = {
|
||||
"cxxtest",
|
||||
}
|
||||
-- 'real' implementations, to be linked against the main executable
|
||||
setup_static_lib_package("mocks_real", {}, extern_libs, { no_default_link = 1, no_default_pch = 1 })
|
||||
listconcat(package.files, matchfiles(source_root.."mocks/*.h", source_root.."mocks/*_real.cpp"))
|
||||
-- 'test' implementations, to be linked against the test executable
|
||||
setup_static_lib_package("mocks_test", {}, extern_libs, { no_default_link = 1, no_default_pch = 1 })
|
||||
listconcat(package.files, matchfiles(source_root.."mocks/*.h", source_root.."mocks/*_test.cpp"))
|
||||
end
|
||||
|
||||
|
||||
@ -563,6 +580,7 @@ function setup_main_exe ()
|
||||
|
||||
package_add_extern_libs(used_extern_libs)
|
||||
|
||||
tinsert(package.links, "mocks_real")
|
||||
|
||||
-- Platform Specifics
|
||||
if OS == "windows" then
|
||||
@ -955,9 +973,9 @@ function setup_tests()
|
||||
package.testoptions = "--have-std"
|
||||
package.rootoptions = "--have-std"
|
||||
if OS == "windows" then
|
||||
package.rootoptions = package.rootoptions .. " --gui=Win32Gui --runner=Win32ODSPrinter"
|
||||
package.rootoptions = package.rootoptions .. " --gui=PsTestWrapper --runner=Win32ODSPrinter"
|
||||
else
|
||||
package.rootoptions = package.rootoptions .. " --runner=ErrorPrinter"
|
||||
package.rootoptions = package.rootoptions .. " --gui=PsTestWrapper --runner=ErrorPrinter"
|
||||
end
|
||||
-- precompiled headers - the header is added to all generated .cpp files
|
||||
-- note that the header isn't actually precompiled here, only #included
|
||||
@ -981,6 +999,7 @@ function setup_tests()
|
||||
-- note: these are not relative to source_root and therefore can't be included via package_add_contents.
|
||||
listconcat(package.files, src_files)
|
||||
package_add_extern_libs(used_extern_libs)
|
||||
tinsert(package.links, "mocks_test")
|
||||
|
||||
if OS == "windows" then
|
||||
-- from "lowlevel" static lib; must be added here to be linked in
|
||||
|
@ -18,22 +18,124 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "lib/external_libraries/boost_filesystem.h"
|
||||
|
||||
#define GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include "mocks/dlfcn.h"
|
||||
#include "mocks/boost_filesystem.h"
|
||||
|
||||
// TODO: This normalization code is copied from boost::filesystem,
|
||||
// where it is deprecated, presumably for good reasons (probably
|
||||
// because symlinks mean "x/../y" != "y" in general), and this file
|
||||
// is not an appropriate place for the code anyway, so it should be
|
||||
// rewritten or removed or something. (Also, the const_cast is evil.)
|
||||
namespace boost { namespace filesystem {
|
||||
|
||||
// Derived from boost/filesystem/path.hpp:
|
||||
// "Copyright Beman Dawes 2002-2005
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)"
|
||||
|
||||
template<class String, class Traits>
|
||||
basic_path<String, Traits> normalize_COPIED(const basic_path<String, Traits> &self)
|
||||
{
|
||||
typedef basic_path<String, Traits> path_type;
|
||||
typedef typename path_type::string_type string_type;
|
||||
typedef typename path_type::iterator iterator;
|
||||
|
||||
static const typename string_type::value_type dot_str[]
|
||||
= { dot<path>::value, 0 };
|
||||
|
||||
if ( self.empty() ) return self;
|
||||
|
||||
path temp;
|
||||
iterator start( self.begin() );
|
||||
iterator last( self.end() );
|
||||
iterator stop( last-- );
|
||||
for ( iterator itr( start ); itr != stop; ++itr )
|
||||
{
|
||||
// ignore "." except at start and last
|
||||
if ( itr->size() == 1
|
||||
&& (*itr)[0] == dot<path_type>::value
|
||||
&& itr != start
|
||||
&& itr != last ) continue;
|
||||
|
||||
// ignore a name and following ".."
|
||||
if ( !temp.empty()
|
||||
&& itr->size() == 2
|
||||
&& (*itr)[0] == dot<path_type>::value
|
||||
&& (*itr)[1] == dot<path_type>::value ) // dot dot
|
||||
{
|
||||
string_type lf( temp.leaf() );
|
||||
if ( lf.size() > 0
|
||||
&& (lf.size() != 1
|
||||
|| (lf[0] != dot<path_type>::value
|
||||
&& lf[0] != slash<path_type>::value))
|
||||
&& (lf.size() != 2
|
||||
|| (lf[0] != dot<path_type>::value
|
||||
&& lf[1] != dot<path_type>::value
|
||||
# ifdef BOOST_WINDOWS_PATH
|
||||
&& lf[1] != colon<path_type>::value
|
||||
# endif
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
temp.remove_leaf();
|
||||
// if not root directory, must also remove "/" if any
|
||||
if ( temp.string().size() > 0
|
||||
&& temp.string()[temp.string().size()-1]
|
||||
== slash<path_type>::value )
|
||||
{
|
||||
typename string_type::size_type rds(
|
||||
detail::root_directory_start<String,Traits>( temp.string(),
|
||||
temp.string().size() ) );
|
||||
if ( rds == string_type::npos
|
||||
|| rds != temp.string().size()-1 )
|
||||
{ const_cast<String&>( temp.string() ).erase( temp.string().size()-1 ); }
|
||||
}
|
||||
|
||||
iterator next( itr );
|
||||
if ( temp.empty() && ++next != stop
|
||||
&& next == last && *last == dot_str ) temp /= dot_str;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
temp /= *itr;
|
||||
};
|
||||
|
||||
if ( temp.empty() ) temp /= dot_str;
|
||||
return temp;
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
LibError sys_get_executable_name(char* n_path, size_t max_chars)
|
||||
{
|
||||
const char* path;
|
||||
Dl_info dl_info;
|
||||
|
||||
// Find the executable's filename
|
||||
memset(&dl_info, 0, sizeof(dl_info));
|
||||
if (!dladdr((void *)sys_get_executable_name, &dl_info) ||
|
||||
if (!T::dladdr((void *)sys_get_executable_name, &dl_info) ||
|
||||
!dl_info.dli_fname )
|
||||
{
|
||||
return ERR::NO_SYS;
|
||||
}
|
||||
path = dl_info.dli_fname;
|
||||
|
||||
strncpy(n_path, dl_info.dli_fname, max_chars);
|
||||
return INFO::OK;
|
||||
// If this looks like a relative path, resolve against cwd.
|
||||
// If this looks like an absolute path, we still need to normalize it.
|
||||
if (strchr(path, '/')) {
|
||||
fs::path p = fs::complete(fs::path(path), T::Boost_Filesystem_initial_path());
|
||||
fs::path n = fs::normalize_COPIED(p);
|
||||
strncpy(n_path, n.string().c_str(), max_chars);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
// If it's not a path at all, i.e. it's just a filename, we'd
|
||||
// probably have to search through PATH to find it.
|
||||
// That's complex and should be uncommon, so don't bother.
|
||||
return ERR::NO_SYS;
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,17 @@
|
||||
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "lib/lib.h"
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "lib/posix/posix.h" // fminf etc.
|
||||
|
||||
#if OS_LINUX
|
||||
# include "mocks/dlfcn.h"
|
||||
# include "mocks/boost_filesystem.h"
|
||||
#endif
|
||||
|
||||
#include <cxxtest/PsTestWrapper.h>
|
||||
|
||||
class TestSysdep : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
@ -68,4 +76,106 @@ public:
|
||||
TS_ASSERT_EQUALS(fmaxf(-2.0f, 1.0f), 1.0f);
|
||||
TS_ASSERT_EQUALS(fmaxf(0.001f, 0.00001f), 0.001f);
|
||||
}
|
||||
|
||||
void test_sys_get_executable_name()
|
||||
{
|
||||
char path[PATH_MAX] = "";
|
||||
|
||||
// Try it first with the real executable (i.e. the
|
||||
// one that's running this test code)
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
// Check it's absolute
|
||||
TSM_ASSERT(std::string("Path: ")+path, path_is_absolute(path));
|
||||
// Check the file exists
|
||||
struct stat s;
|
||||
TSM_ASSERT_EQUALS(std::string("Path: ")+path, stat(path, &s), 0);
|
||||
|
||||
// Do some platform-specific tests, based on the
|
||||
// implementations of sys_get_executable_name:
|
||||
|
||||
#if OS_LINUX
|
||||
// Try with absolute paths
|
||||
{
|
||||
Mock_dladdr d("/example/executable");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/executable");
|
||||
}
|
||||
{
|
||||
Mock_dladdr d("/example/./a/b/../c/../../executable");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/executable");
|
||||
}
|
||||
|
||||
// Try with relative paths
|
||||
{
|
||||
Mock_dladdr d("./executable");
|
||||
Mock_initial_path m("/example");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/executable");
|
||||
}
|
||||
{
|
||||
Mock_dladdr d("./executable");
|
||||
Mock_initial_path m("/example/");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/executable");
|
||||
}
|
||||
{
|
||||
Mock_dladdr d("../d/../../e/executable");
|
||||
Mock_initial_path m("/example/a/b/c");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/a/e/executable");
|
||||
}
|
||||
|
||||
// Try with pathless names
|
||||
{
|
||||
Mock_dladdr d("executable");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), ERR::NO_SYS);
|
||||
}
|
||||
#endif // OS_LINUX
|
||||
}
|
||||
|
||||
// Mock classes for test_sys_get_executable_name
|
||||
#if OS_LINUX
|
||||
class Mock_dladdr : public T::Base_dladdr
|
||||
{
|
||||
public:
|
||||
Mock_dladdr(const char* fname) : fname_(fname) { }
|
||||
int dladdr(void *UNUSED(addr), Dl_info *info) {
|
||||
info->dli_fname = fname_;
|
||||
return 1;
|
||||
}
|
||||
private:
|
||||
const char* fname_;
|
||||
};
|
||||
|
||||
class Mock_initial_path : public T::Base_Boost_Filesystem_initial_path
|
||||
{
|
||||
public:
|
||||
Mock_initial_path(const char* buf) : buf_(buf) { }
|
||||
fs::path Boost_Filesystem_initial_path() {
|
||||
return fs::path(buf_);
|
||||
}
|
||||
private:
|
||||
const char* buf_;
|
||||
};
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool path_is_absolute(const char* path)
|
||||
{
|
||||
// UNIX-style absolute paths
|
||||
if (path[0] == '/')
|
||||
return true;
|
||||
|
||||
// Windows UNC absolute paths
|
||||
if (path[0] == '\\' && path[1] == '\\')
|
||||
return true;
|
||||
|
||||
// Windows drive-letter absolute paths
|
||||
if (isalpha(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\'))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
10
source/mocks/boost_filesystem.h
Normal file
10
source/mocks/boost_filesystem.h
Normal file
@ -0,0 +1,10 @@
|
||||
#include "lib/external_libraries/boost_filesystem.h"
|
||||
#include <cxxtest/Mock.h>
|
||||
CXXTEST_MOCK(
|
||||
Boost_Filesystem_initial_path,
|
||||
boost::filesystem::path,
|
||||
Boost_Filesystem_initial_path,
|
||||
(),
|
||||
boost::filesystem::initial_path,
|
||||
()
|
||||
);
|
7
source/mocks/dlfcn.h
Normal file
7
source/mocks/dlfcn.h
Normal file
@ -0,0 +1,7 @@
|
||||
#include <dlfcn.h>
|
||||
#include <cxxtest/Mock.h>
|
||||
CXXTEST_MOCK_GLOBAL(
|
||||
int, dladdr,
|
||||
(void *addr, Dl_info *info),
|
||||
(addr, info)
|
||||
);
|
8
source/mocks/mocks_real.cpp
Normal file
8
source/mocks/mocks_real.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#define CXXTEST_MOCK_REAL_SOURCE_FILE
|
||||
#include "lib/sysdep/os.h"
|
||||
|
||||
#include "mocks/boost_filesystem.h"
|
||||
|
||||
#if OS_LINUX
|
||||
#include "mocks/dlfcn.h"
|
||||
#endif // OS_LINUX
|
15
source/mocks/mocks_test.cpp
Normal file
15
source/mocks/mocks_test.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#define CXXTEST_MOCK_TEST_SOURCE_FILE
|
||||
#include "lib/sysdep/os.h"
|
||||
|
||||
// Cause calls to be redirected to the real function by default
|
||||
#define DEFAULT(name) static T::Real_##name real_##name
|
||||
|
||||
#include "mocks/boost_filesystem.h"
|
||||
DEFAULT(Boost_Filesystem_initial_path);
|
||||
|
||||
#if OS_LINUX
|
||||
|
||||
#include "mocks/dlfcn.h"
|
||||
DEFAULT(dladdr);
|
||||
|
||||
#endif // OS_LINUX
|
Loading…
Reference in New Issue
Block a user