diff --git a/include/gtest/internal/gtest-death-test-internal.h b/include/gtest/internal/gtest-death-test-internal.h index 46afbe1d..143e58a9 100644 --- a/include/gtest/internal/gtest-death-test-internal.h +++ b/include/gtest/internal/gtest-death-test-internal.h @@ -197,7 +197,7 @@ class InternalRunDeathTestFlag { ~InternalRunDeathTestFlag() { if (write_fd_ >= 0) - posix::close(write_fd_); + posix::Close(write_fd_); } String file() const { return file_; } diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 4267a58f..48e740ba 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -725,43 +725,43 @@ typedef long long BiggestInt; // NOLINT // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between -// Windows/MSVC and POSIX systems. +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + namespace posix { // Functions with a different name on Windows. #if GTEST_OS_WINDOWS -typedef struct _stat stat_struct; +typedef struct _stat StatStruct; -// We cannot write ::_fileno() as MSVC defines it as a macro. -inline int fileno(FILE* file) { return _fileno(file); } -inline int isatty(int fd) { return ::_isatty(fd); } -inline int stat(const char* path, stat_struct* buf) { - return ::_stat(path, buf); +inline int FileNo(FILE* file) { return _fileno(file); } +inline int IsATTY(int fd) { return _isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); } -inline int strcasecmp(const char* s1, const char* s2) { - return ::_stricmp(s1, s2); -} -// We cannot define the function as strdup(const char* src), since -// MSVC defines strdup as a macro. -inline char* StrDup(const char* src) { return ::_strdup(src); } -inline int rmdir(const char* dir) { return ::_rmdir(dir); } -inline bool IsDir(const stat_struct& st) { +inline char* StrDup(const char* src) { return _strdup(src); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return (_S_IFDIR & st.st_mode) != 0; } #else -typedef struct stat stat_struct; +typedef struct stat StatStruct; -using ::fileno; -using ::isatty; -using ::stat; -using ::strcasecmp; +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} inline char* StrDup(const char* src) { return ::strdup(src); } -using ::rmdir; -inline bool IsDir(const stat_struct& st) { return S_ISDIR(st.st_mode); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS @@ -773,38 +773,31 @@ inline bool IsDir(const stat_struct& st) { return S_ISDIR(st.st_mode); } #pragma warning(disable:4996) #endif -inline const char* strncpy(char* dest, const char* src, size_t n) { - return ::strncpy(dest, src, n); +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); } - -inline int chdir(const char* dir) { return ::chdir(dir); } - -inline FILE* fopen(const char* path, const char* mode) { - return ::fopen(path, mode); +inline int ChDir(const char* dir) { return chdir(dir); } +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); } -inline FILE *freopen(const char *path, const char *mode, FILE *stream) { - return ::freopen(path, mode, stream); +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); } -inline FILE* fdopen(int fd, const char* mode) { - return ::fdopen(fd, mode); +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +inline int FClose(FILE* fp) { return fclose(fp); } +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); } -inline int fclose(FILE *fp) { return ::fclose(fp); } - -inline int read(int fd, void* buf, unsigned int count) { - return static_cast(::read(fd, buf, count)); +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); } -inline int write(int fd, const void* buf, unsigned int count) { - return static_cast(::write(fd, buf, count)); -} -inline int close(int fd) { return ::close(fd); } - -inline const char* strerror(int errnum) { return ::strerror(errnum); } - -inline const char* getenv(const char* name) { +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +inline const char* GetEnv(const char* name) { #ifdef _WIN32_WCE // We are on Windows CE, which has no environment variables. return NULL; #else - return ::getenv(name); + return getenv(name); #endif } @@ -816,9 +809,9 @@ inline const char* getenv(const char* name) { // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. -void abort(); +void Abort(); #else -using ::abort; +inline void Abort() { abort(); } #endif // _WIN32_WCE } // namespace posix diff --git a/scons/SConscript b/scons/SConscript index 6a7cc137..21b5ab5a 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -131,6 +131,10 @@ gtest_ex_obj = env_with_exceptions.Object(target='gtest_ex', gtest_main_ex_obj = env_with_exceptions.Object(target='gtest_main_ex', source=gtest_main_source) +gtest_ex = env_with_exceptions.StaticLibrary( + target='gtest_ex', + source=gtest_ex_obj) + gtest_ex_main = env_with_exceptions.StaticLibrary( target='gtest_ex_main', source=gtest_ex_obj + gtest_main_ex_obj) @@ -204,14 +208,24 @@ GtestUnitTest(env, 'gtest_output_test_', gtest) GtestUnitTest(env, 'gtest_color_test_', gtest) GtestUnitTest(env, 'gtest-linked_ptr_test', gtest_main) GtestUnitTest(env, 'gtest-port_test', gtest_main) +GtestUnitTest(env, 'gtest_break_on_failure_unittest_', gtest) +GtestUnitTest(env, 'gtest_filter_unittest_', gtest) +GtestUnitTest(env, 'gtest_help_test_', gtest_main) +GtestUnitTest(env, 'gtest_list_tests_unittest_', gtest) +GtestUnitTest(env, 'gtest_throw_on_failure_test_', gtest) +GtestUnitTest(env_with_exceptions, 'gtest_throw_on_failure_ex_test', gtest_ex) +GtestUnitTest(env, 'gtest_xml_outfile1_test_', gtest_main) +GtestUnitTest(env, 'gtest_xml_outfile2_test_', gtest_main) +GtestUnitTest(env, 'gtest_xml_output_unittest_', gtest_main) -env_with_pthread = env.Clone() -if env_with_pthread['PLATFORM'] not in ['win32', 'darwin']: - # Assuming POSIX-like environment with GCC. - env_with_pthread.Append(CCFLAGS = ['-pthread']) - env_with_pthread.Append(LINKFLAGS = ['-pthread']) - -GtestUnitTest(env_with_pthread, 'gtest-death-test_test', gtest_main) +# Assuming POSIX-like environment with GCC. +# TODO(vladl@google.com): sniff presence of pthread_atfork instead of +# selecting on a platform. +env_with_threads = env.Clone() +if env_with_threads['PLATFORM'] != 'win32': + env_with_threads.Append(CCFLAGS = ['-pthread']) + env_with_threads.Append(LINKFLAGS = ['-pthread']) +GtestUnitTest(env_with_threads, 'gtest-death-test_test', gtest_main) gtest_unittest_ex_obj = env_with_exceptions.Object( target='gtest_unittest_ex', @@ -221,17 +235,6 @@ GtestBinary(env_with_exceptions, gtest_ex_main, gtest_unittest_ex_obj) -# TODO(wan@google.com) Add these unit tests: -# - gtest_break_on_failure_unittest_ -# - gtest_filter_unittest_ -# - gtest_help_test_ -# - gtest_list_tests_unittest_ -# - gtest_throw_on_failure_ex_test -# - gtest_throw_on_failure_test_ -# - gtest_xml_outfile1_test_ -# - gtest_xml_outfile2_test_ -# - gtest_xml_output_unittest_ - # We need to disable some optimization flags for some tests on # Windows; otherwise the redirection of stdout does not work # (apparently because of a compiler bug). diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 517495b5..0d4110bd 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -204,7 +204,7 @@ void DeathTestAbort(const String& message) { const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { - FILE* parent = posix::fdopen(flag->write_fd(), "w"); + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); @@ -249,7 +249,7 @@ void DeathTestAbort(const String& message) { // Returns the message describing the last system error in errno. String GetLastErrnoDescription() { - return String(errno == 0 ? "" : posix::strerror(errno)); + return String(errno == 0 ? "" : posix::StrError(errno)); } // This is called from a death test parent process to read a failure @@ -262,7 +262,7 @@ static void FailFromInternalError(int fd) { int num_read; do { - while ((num_read = posix::read(fd, buffer, 255)) > 0) { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } @@ -380,7 +380,7 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { // its success), so it's okay to call this in the parent before // the child process has exited. do { - bytes_read = posix::read(read_fd(), &flag, 1); + bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { @@ -407,7 +407,7 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { Message() << "Read from death test child process failed: " << GetLastErrnoDescription()); } - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::close(read_fd())); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } @@ -421,8 +421,8 @@ void DeathTestImpl::Abort(AbortReason reason) { // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::write(write_fd(), &status_ch, 1)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::close(write_fd())); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 7ba6a6b7..3180d0d5 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -168,8 +168,8 @@ bool FilePath::FileOrDirectoryExists() const { delete [] unicode; return attributes != kInvalidFileAttributes; #else - posix::stat_struct file_stat; - return posix::stat(pathname_.c_str(), &file_stat) == 0; + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; #endif // _WIN32_WCE } @@ -195,8 +195,8 @@ bool FilePath::DirectoryExists() const { result = true; } #else - posix::stat_struct file_stat; - result = posix::stat(path.c_str(), &file_stat) == 0 && + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); #endif // _WIN32_WCE diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 3c1e80c2..e5c793f8 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -539,9 +539,9 @@ void CaptureStderr() { ::std::string GetCapturedStderr() { g_captured_stderr->StopCapture(); - FILE* const file = posix::fopen(g_captured_stderr->filename().c_str(), "r"); + FILE* const file = posix::FOpen(g_captured_stderr->filename().c_str(), "r"); const ::std::string content = ReadEntireFile(file); - posix::fclose(file); + posix::FClose(file); delete g_captured_stderr; g_captured_stderr = NULL; @@ -563,7 +563,7 @@ const ::std::vector& GetArgvs() { return g_argvs; } #ifdef _WIN32_WCE namespace posix { -void abort() { +void Abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } @@ -632,7 +632,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { const String env_var = FlagToEnvVar(flag); - const char* const string_value = posix::getenv(env_var.c_str()); + const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; } @@ -642,7 +642,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) { // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { const String env_var = FlagToEnvVar(flag); - const char* const string_value = posix::getenv(env_var.c_str()); + const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { // The environment variable is not set. return default_value; @@ -664,7 +664,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { const String env_var = FlagToEnvVar(flag); - const char* const value = posix::getenv(env_var.c_str()); + const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; } diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index b9ca6b73..9aacd2be 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -81,7 +81,7 @@ void TestPartResultArray::Append(const TestPartResult& result) { const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - internal::posix::abort(); + internal::posix::Abort(); } const internal::ListNode* p = list_->Head(); diff --git a/src/gtest.cc b/src/gtest.cc index b77f62e7..6e01c1be 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -803,7 +803,7 @@ static char* CloneString(const char* str, size_t length) { return NULL; } else { char* const clone = new char[length + 1]; - posix::strncpy(clone, str, length); + posix::StrNCpy(clone, str, length); clone[length] = '\0'; return clone; } @@ -1443,7 +1443,7 @@ char* CodePointToUtf8(UInt32 code_point, char* str) { // the terminating nul character). We are asking for 32 character // buffer just in case. This is also enough for strncpy to // null-terminate the destination string. - posix::strncpy( + posix::StrNCpy( str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); str[31] = '\0'; // Makes sure no change in the format to strncpy leaves // the result unterminated. @@ -1586,7 +1586,7 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { return rhs == NULL; if (rhs == NULL) return false; - return posix::strcasecmp(lhs, rhs) == 0; + return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they @@ -2510,7 +2510,7 @@ bool ShouldUseColor(bool stdout_is_tty) { return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. - const char* const term = posix::getenv("TERM"); + const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || @@ -2540,7 +2540,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { const bool use_color = false; #else static const bool in_color_mode = - ShouldUseColor(posix::isatty(posix::fileno(stdout)) != 0); + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. @@ -2622,8 +2622,8 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart( if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %s of %s.\n", - internal::posix::getenv(kTestShardIndex), - internal::posix::getenv(kTestTotalShards)); + internal::posix::GetEnv(kTestShardIndex), + internal::posix::GetEnv(kTestTotalShards)); } const internal::UnitTestImpl* const impl = unit_test->impl(); @@ -2941,7 +2941,7 @@ void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) { internal::FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { - xmlout = internal::posix::fopen(output_file_.c_str(), "w"); + xmlout = internal::posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. @@ -3678,9 +3678,9 @@ int UnitTestImpl::RunAllTests() { // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { - const char* const test_shard_file = posix::getenv(kTestShardStatusFile); + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != NULL) { - FILE* const file = posix::fopen(test_shard_file, "w"); + FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " @@ -3745,7 +3745,7 @@ bool ShouldShard(const char* total_shards_env, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { - const char* str_val = posix::getenv(var); + const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; } diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc index db5f72e0..9dd477b2 100644 --- a/test/gtest-death-test_test.cc +++ b/test/gtest-death-test_test.cc @@ -106,7 +106,7 @@ class TestForDeathTest : public testing::Test { TestForDeathTest() : original_dir_(FilePath::GetCurrentDir()) {} virtual ~TestForDeathTest() { - posix::chdir(original_dir_.c_str()); + posix::ChDir(original_dir_.c_str()); } // A static member function that's expected to die. @@ -345,7 +345,7 @@ TEST_F(TestForDeathTest, MemberFunctionFastStyle) { EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); } -void ChangeToRootDir() { posix::chdir(GTEST_PATH_SEP_); } +void ChangeToRootDir() { posix::ChDir(GTEST_PATH_SEP_); } // Tests that death tests work even if the current directory has been // changed. diff --git a/test/gtest-filepath_test.cc b/test/gtest-filepath_test.cc index 77a2988e..b6d950dd 100644 --- a/test/gtest-filepath_test.cc +++ b/test/gtest-filepath_test.cc @@ -86,9 +86,9 @@ TEST(GetCurrentDirTest, ReturnsCurrentDir) { const FilePath original_dir = FilePath::GetCurrentDir(); EXPECT_FALSE(original_dir.IsEmpty()); - posix::chdir(GTEST_PATH_SEP_); + posix::ChDir(GTEST_PATH_SEP_); const FilePath cwd = FilePath::GetCurrentDir(); - posix::chdir(original_dir.c_str()); + posix::ChDir(original_dir.c_str()); #if GTEST_OS_WINDOWS // Skips the ":". @@ -435,14 +435,14 @@ class DirectoryCreationTest : public Test { remove(testdata_file_.c_str()); remove(unique_file0_.c_str()); remove(unique_file1_.c_str()); - posix::rmdir(testdata_path_.c_str()); + posix::RmDir(testdata_path_.c_str()); } virtual void TearDown() { remove(testdata_file_.c_str()); remove(unique_file0_.c_str()); remove(unique_file1_.c_str()); - posix::rmdir(testdata_path_.c_str()); + posix::RmDir(testdata_path_.c_str()); } String TempDir() const { @@ -450,7 +450,7 @@ class DirectoryCreationTest : public Test { return String("\\temp\\"); #elif GTEST_OS_WINDOWS - const char* temp_dir = posix::getenv("TEMP"); + const char* temp_dir = posix::GetEnv("TEMP"); if (temp_dir == NULL || temp_dir[0] == '\0') return String("\\temp\\"); else if (String(temp_dir).EndsWith("\\")) @@ -463,7 +463,7 @@ class DirectoryCreationTest : public Test { } void CreateTextFile(const char* filename) { - FILE* f = posix::fopen(filename, "w"); + FILE* f = posix::FOpen(filename, "w"); fprintf(f, "text\n"); fclose(f); } diff --git a/test/gtest-options_test.cc b/test/gtest-options_test.cc index d49efe49..43c6d22d 100644 --- a/test/gtest-options_test.cc +++ b/test/gtest-options_test.cc @@ -150,14 +150,14 @@ class XmlOutputChangeDirTest : public Test { protected: virtual void SetUp() { original_working_dir_ = FilePath::GetCurrentDir(); - posix::chdir(".."); + posix::ChDir(".."); // This will make the test fail if run from the root directory. EXPECT_STRNE(original_working_dir_.c_str(), FilePath::GetCurrentDir().c_str()); } virtual void TearDown() { - posix::chdir(original_working_dir_.c_str()); + posix::ChDir(original_working_dir_.c_str()); } FilePath original_working_dir_; diff --git a/test/gtest_output_test_.cc b/test/gtest_output_test_.cc index 4d7f0758..9c92d8cc 100644 --- a/test/gtest_output_test_.cc +++ b/test/gtest_output_test_.cc @@ -991,9 +991,9 @@ int main(int argc, char **argv) { // Skip the usual output capturing if we're running as the child // process of an threadsafe-style death test. #if GTEST_OS_WINDOWS - posix::freopen("nul:", "w", stdout); + posix::FReopen("nul:", "w", stdout); #else - posix::freopen("/dev/null", "w", stdout); + posix::FReopen("/dev/null", "w", stdout); #endif // GTEST_OS_WINDOWS return RUN_ALL_TESTS(); } diff --git a/test/gtest_throw_on_failure_test.py b/test/gtest_throw_on_failure_test.py index 50172d07..e952da5a 100755 --- a/test/gtest_throw_on_failure_test.py +++ b/test/gtest_throw_on_failure_test.py @@ -72,7 +72,8 @@ def Run(command): """Runs a command; returns True/False if its exit code is/isn't 0.""" print 'Running "%s". . .' % ' '.join(command) - return gtest_test_utils.Subprocess(command).exit_code == 0 + p = gtest_test_utils.Subprocess(command) + return p.exited and p.exit_code == 0 # The tests. TODO(wan@google.com): refactor the class to share common