diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sal/qa/osl | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sal/qa/osl')
23 files changed, 11725 insertions, 0 deletions
diff --git a/sal/qa/osl/condition/osl_Condition.cxx b/sal/qa/osl/condition/osl_Condition.cxx new file mode 100644 index 0000000000..9bc15b92b6 --- /dev/null +++ b/sal/qa/osl/condition/osl_Condition.cxx @@ -0,0 +1,333 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> +#include <osl/thread.hxx> +#include <osl/conditn.hxx> +#include <osl/time.h> + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +using namespace osl; + +namespace { + +enum ConditionType +{ + thread_type_set, + thread_type_reset, + thread_type_wait +}; + +/** thread for testing Condition. + */ +class ConditionThread : public Thread +{ +public: + //get the Condition to operate + ConditionThread( ::osl::Condition& Con, ConditionType tType): m_MyCon( Con ), m_MyType( tType ) { } + +protected: + ::osl::Condition& m_MyCon; + ConditionType m_MyType; + + void SAL_CALL run() override + { + switch ( m_MyType ) + { + case thread_type_wait: + m_MyCon.wait(); break; + case thread_type_set: + m_MyCon.set(); break; + case thread_type_reset: + m_MyCon.reset(); break; + default: + break; + } + } +}; + +} + +namespace osl_Condition +{ + /** testing the method: + Condition() + */ + class ctors : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void ctors_create() + { + ::osl::Condition aCond; + bRes = aCond.check(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: create a condition its initial check state should be sal_False.", + !bRes ); + } + + void ctors_createAndSet() + { + ::osl::Condition aCond; + aCond.set(); + bRes = aCond.check(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: create a condition and set it.", + bRes ); + } + + CPPUNIT_TEST_SUITE(ctors); + CPPUNIT_TEST(ctors_create); + CPPUNIT_TEST(ctors_createAndSet); + CPPUNIT_TEST_SUITE_END(); + }; + + /** testing the method: + void set() + */ + class set : public CppUnit::TestFixture + { + public: + bool bRes, bRes1, bRes2; + + void set_createAndSet() + { + ::osl::Condition aCond; + aCond.set(); + bRes = aCond.check(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: check state should be sal_True after set.", + bRes ); + } + + void set_threadWaitRelease() + { + ::osl::Condition aCond; + ConditionThread myThread1(aCond, thread_type_wait); + myThread1.create(); + bRes = myThread1.isRunning(); + + ConditionThread myThread2(aCond, thread_type_set); + myThread2.create(); + + myThread1.join(); + bRes1 = myThread1.isRunning(); + bRes2 = aCond.check(); + myThread2.join(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: use one thread to set the condition in order to release another thread.", + bRes); + CPPUNIT_ASSERT_MESSAGE("#test comment#: use one thread to set the condition in order to release another thread.", + !bRes1); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: use one thread to set the condition in order to release another thread.", + bRes2); + } + + CPPUNIT_TEST_SUITE(set); + CPPUNIT_TEST(set_createAndSet); + CPPUNIT_TEST(set_threadWaitRelease); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the method: + void reset() + */ + class reset : public CppUnit::TestFixture + { + public: + bool bRes, bRes1, bRes2; + + void reset_resetWaitAndSet() + { + ::osl::Condition aCond; + aCond.reset(); + + ConditionThread myThread(aCond, thread_type_wait); + myThread.create(); + bRes = myThread.isRunning(); + bRes2 = aCond.check(); + + aCond.set(); + myThread.join(); + bRes1 = myThread.isRunning(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: wait will cause a reset thread block, use set to release it.", + bRes); + CPPUNIT_ASSERT_MESSAGE("#test comment#: wait will cause a reset thread block, use set to release it.", + !bRes1); + CPPUNIT_ASSERT_MESSAGE("#test comment#: wait will cause a reset thread block, use set to release it.", + !bRes2); + } + + void reset_resetAndSet() + { + ::osl::Condition aCond; + aCond.reset(); + bRes = aCond.check(); + aCond.set(); + bRes1 = aCond.check(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: create a condition and reset/set it.", + !bRes ); + CPPUNIT_ASSERT_MESSAGE("#test comment#: create a condition and reset/set it.", + bRes1 ); + } + + CPPUNIT_TEST_SUITE(reset); + CPPUNIT_TEST(reset_resetWaitAndSet); + CPPUNIT_TEST(reset_resetAndSet); + CPPUNIT_TEST_SUITE_END(); + }; + + /** testing the method: + Result wait(const TimeValue *pTimeout = 0) + */ + class wait : public CppUnit::TestFixture + { + public: + bool bRes, bRes1, bRes2; + std::unique_ptr<TimeValue> tv1; + + void setUp() override + { + tv1.reset(new TimeValue); + tv1->Seconds = 1; + tv1->Nanosec = 0; + } + + void tearDown() override + { + tv1.reset(); + } + + void wait_testAllCombos( ) + { + ::osl::Condition cond1; + ::osl::Condition cond2; + ::osl::Condition cond3; + + cond1.set(); + cond2.set(); + + osl::Condition::Result r1=cond1.wait(tv1.get()); + osl::Condition::Result r2=cond2.wait(); + osl::Condition::Result r3=cond3.wait(tv1.get()); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "#test comment#: test three types of wait.", + ::osl::Condition::result_ok, r1 ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "#test comment#: test three types of wait.", + ::osl::Condition::result_ok, r2 ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "#test comment#: test three types of wait.", + ::osl::Condition::result_timeout, r3 ); + } + + void wait_timeoutWaits() + { + ::osl::Condition aCond; + ::osl::Condition::Result wRes, wRes1; + + aCond.reset(); + bRes = aCond.check(); + wRes = aCond.wait(tv1.get()); + + aCond.set(); + wRes1 = aCond.wait(tv1.get()); + bRes1 = aCond.check(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: wait a condition after set/reset.", + !bRes ); + CPPUNIT_ASSERT_MESSAGE("#test comment#: wait a condition after set/reset.", + bRes1 ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("#test comment#: wait a condition after set/reset.", + ::osl::Condition::result_timeout, wRes ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("#test comment#: wait a condition after set/reset.", + ::osl::Condition::result_ok, wRes1 ); + } + + CPPUNIT_TEST_SUITE(wait); + CPPUNIT_TEST(wait_testAllCombos); + CPPUNIT_TEST(wait_timeoutWaits); + CPPUNIT_TEST_SUITE_END(); + }; + + /** testing the method: + sal_Bool check() + */ + class check : public CppUnit::TestFixture + { + public: + bool bRes, bRes1, bRes2; + + void check_checkStates() + { + ::osl::Condition aCond; + + aCond.reset(); + bRes = aCond.check(); + aCond.set(); + bRes1 = aCond.check(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: check the condition states.", + !bRes ); + CPPUNIT_ASSERT_MESSAGE("#test comment#: check the condition states.", + bRes1 ); + } + + void check_threadedCheckStates( ) + { + ::osl::Condition aCond; + aCond.reset(); + + ConditionThread myThread(aCond, thread_type_set); + myThread.create(); + myThread.join(); + bRes = aCond.check(); + + ConditionThread myThread1(aCond, thread_type_reset); + myThread1.create(); + myThread1.join(); + bRes1 = aCond.check(); + + CPPUNIT_ASSERT_MESSAGE("#test comment#: use threads to set/reset Condition and check it in main routine.", + bRes ); + CPPUNIT_ASSERT_MESSAGE("#test comment#: use threads to set/reset Condition and check it in main routine.", + !bRes1 ); + } + + CPPUNIT_TEST_SUITE(check); + CPPUNIT_TEST(check_checkStates); + CPPUNIT_TEST(check_threadedCheckStates); + CPPUNIT_TEST_SUITE_END(); + }; + + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Condition::ctors); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Condition::set); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Condition::reset); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Condition::wait); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Condition::check); + +} // namespace osl_Condition + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/file/osl_File.cxx b/sal/qa/osl/file/osl_File.cxx new file mode 100644 index 0000000000..6b0c50dfaf --- /dev/null +++ b/sal/qa/osl/file/osl_File.cxx @@ -0,0 +1,4976 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> +#include <rtl/byteseq.hxx> +#include <rtl/ustring.hxx> + +#include <osl/file.hxx> +#include "osl_File_Const.h" + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <memory> + +#ifdef _WIN32 +#include <prewin.h> +#include <postwin.h> +#include <o3tl/char16_t2wchar_t.hxx> +#include <tools/urlobj.hxx> +#endif + +using namespace osl; + +/** detailed wrong message. +*/ +static OString errorToString(const osl::FileBase::RC _nError) +{ + OString sResult; + switch (_nError) { + case osl::FileBase::E_None: + sResult = "Success"_ostr; + break; + case osl::FileBase::E_PERM: + sResult = "Operation not permitted"_ostr; + break; + case osl::FileBase::E_NOENT: + sResult = "No such file or directory"_ostr; + break; + case osl::FileBase::E_EXIST: + sResult = "Already Exist"_ostr; + break; + case osl::FileBase::E_ACCES: + sResult = "Permission denied"_ostr; + break; + case osl::FileBase::E_INVAL: + sResult = "The format of the parameters was not valid"_ostr; + break; + case osl::FileBase::E_NOTDIR: + sResult = "Not a directory"_ostr; + break; + case osl::FileBase::E_ISDIR: + sResult = "Is a directory"_ostr; + break; + case osl::FileBase::E_BADF: + sResult = "Bad file"_ostr; + break; + case osl::FileBase::E_NOTEMPTY: + sResult = "The directory is not empty"_ostr; + break; + default: + sResult = "Unknown Error"_ostr; + break; + } + return sResult; +} + +static OString errorToStr(osl::FileBase::RC const& nError) +{ + OString suBuf = "The returned error is: " + + errorToString(nError) + + "!\n"; + return suBuf; +} + +/** compare two TimeValue, unit is "ms", since Windows time precision is better than UNX. +*/ +/* FIXME: the above assertion is bogus */ + +#if (defined UNX) // precision of time in Windows is better than UNX +# define delta 2000 // time precision, 2000ms +#else +# define delta 1800 // time precision, 1.8s +#endif + +static bool t_compareTime(TimeValue *m_aEndTime, TimeValue *m_aStartTime, sal_Int32 nDelta) +{ + sal_Int32 nDeltaSeconds = m_aEndTime->Seconds - m_aStartTime->Seconds; + sal_Int32 nDeltaNanoSec = sal_Int32(m_aEndTime->Nanosec) - sal_Int32(m_aStartTime->Nanosec); + if (nDeltaNanoSec < 0) + { + nDeltaNanoSec = 1000000000 + nDeltaNanoSec; + nDeltaSeconds--; + } + + sal_Int32 nDeltaMilliSec = (nDeltaSeconds * 1000) + (nDeltaNanoSec / 1000000); + return (nDeltaMilliSec < nDelta); +} + +/** compare two OUString file name. +*/ +static bool compareFileName(const OUString & ustr1, const OUString & ustr2) +{ + bool bOk; +// on Windows, the separator is '\', so here change to '/', then compare +#if defined(_WIN32) + OUString ustr1new,ustr2new; + sal_Unicode reverseSlash = '\\'; + + if (ustr1.lastIndexOf(reverseSlash) != -1) + ustr1new = ustr1.replace(reverseSlash,'/'); + else + ustr1new = ustr1; + if (ustr2.lastIndexOf(reverseSlash) != -1) + ustr2new = ustr2.replace(reverseSlash,'/'); + else + ustr2new = ustr2; + bOk = ustr1new.equalsIgnoreAsciiCase(ustr2new); +#else + bOk = ustr1.equalsIgnoreAsciiCase(ustr2); +#endif + return bOk; +} + +/** simple version to judge if a file name or directory name is a URL or a system path, just to see if it + is start with "file:///";. +*/ +static bool isURL(const OUString& pathname) +{ + return pathname.startsWith(aPreURL); +} + +/** concat two part to form a URL or system path, add PATH_SEPARATOR between them if necessary, add "file:///" to beginning if necessary. +*/ +static void concatURL(OUString & pathname1, const OUString & pathname2) +{ + // check if pathname1 is full qualified URL; + if (!isURL(pathname1)) + { + OUString aPathName = pathname1.copy(0); + osl::FileBase::getFileURLFromSystemPath(pathname1, aPathName); // convert if not full qualified URL + pathname1 = aPathName.copy(0); + } + + // check if '/' is in the end of pathname1 or at the begin of pathname2; + if (!pathname1.endsWith(aSlashURL) && !pathname2.startsWith(aSlashURL)) + pathname1 += aSlashURL; + pathname1 += pathname2; +} + +/** create a temp test file using OUString name of full qualified URL or system path. +*/ +static void createTestFile(const OUString& filename) +{ + OUString aPathURL = filename.copy(0); + osl::FileBase::RC nError; + + if (!isURL(filename)) + osl::FileBase::getFileURLFromSystemPath(filename, aPathURL); // convert if not full qualified URL + + File aFile(aPathURL); + nError = aFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); + if ((nError != osl::FileBase::E_None) && (nError != osl::FileBase::E_EXIST)) + printf("createTestFile failed!\n"); + + aFile.close(); + +} + +/** create a temp test file using OUString name of full qualified URL or system path in a base directory. +*/ +static void createTestFile(const OUString& basename, const OUString& filename) +{ + OUString aBaseURL = basename.copy(0); + + concatURL(aBaseURL, filename); + createTestFile(aBaseURL); +} + +/** delete a temp test file using OUString name. +*/ +static void deleteTestFile(const OUString& filename) +{ + OUString aPathURL = filename.copy(0); + osl::FileBase::RC nError; + + if (!isURL(filename)) + osl::FileBase::getFileURLFromSystemPath(filename, aPathURL); // convert if not full qualified URL + + nError = File::setAttributes(aPathURL, osl_File_Attribute_GrpWrite| osl_File_Attribute_OwnWrite| osl_File_Attribute_OthWrite); // if readonly, make writable. + CPPUNIT_ASSERT_MESSAGE("In deleteTestFile Function: set writable ", (osl::FileBase::E_None == nError) || (osl::FileBase::E_NOENT == nError)); + + nError = File::remove(aPathURL); + CPPUNIT_ASSERT_MESSAGE("In deleteTestFile Function: remove ", (osl::FileBase::E_None == nError) || (nError == osl::FileBase::E_NOENT)); +} + +/** delete a temp test file using OUString name of full qualified URL or system path in a base directory. +*/ +static void deleteTestFile(const OUString& basename, const OUString& filename) +{ + OUString aBaseURL = basename.copy(0); + + concatURL(aBaseURL, filename); + deleteTestFile(aBaseURL); +} + +/** create a temp test directory using OUString name of full qualified URL or system path. +*/ +static void createTestDirectory(const OUString& dirname) +{ + OUString aPathURL = dirname.copy(0); + osl::FileBase::RC nError; + + if (!isURL(dirname)) + osl::FileBase::getFileURLFromSystemPath(dirname, aPathURL); // convert if not full qualified URL + nError = Directory::create(aPathURL); + if ((nError != osl::FileBase::E_None) && (nError != osl::FileBase::E_EXIST)) + printf("createTestDirectory failed: %d!\n", int(nError)); +} + +/** create a temp test directory using OUString name of full qualified URL or system path in a base directory. +*/ +static void createTestDirectory(const OUString& basename, const OUString& dirname) +{ + OUString aBaseURL = basename.copy(0); + + concatURL(aBaseURL, dirname); + createTestDirectory(aBaseURL); +} + +/** delete a temp test directory using OUString name of full qualified URL or system path. +*/ +static void deleteTestDirectory(const OUString& dirname) +{ + OUString aPathURL = dirname.copy(0); + if (!isURL(dirname)) + osl::FileBase::getFileURLFromSystemPath(dirname, aPathURL); // convert if not full qualified URL + + Directory testDir(aPathURL); + if (testDir.isOpen()) + testDir.close(); // close if still open. + + osl::FileBase::RC nError = Directory::remove(aPathURL); + + OString strError = "In deleteTestDirectory function: remove Directory " + + OUStringToOString(aPathURL, RTL_TEXTENCODING_ASCII_US) + " -> result: " + OString::number(nError); + CPPUNIT_ASSERT_MESSAGE(strError.getStr(), (osl::FileBase::E_None == nError) || (nError == osl::FileBase::E_NOENT)); +} + +/** delete a temp test directory using OUString name of full qualified URL or system path in a base directory. +*/ +static void deleteTestDirectory(const OUString& basename, const OUString& dirname) +{ + OUString aBaseURL = basename.copy(0); + + concatURL(aBaseURL, dirname); + deleteTestDirectory(aBaseURL); +} + +namespace { + +/** Check for the file and directory access right. +*/ +enum class oslCheckMode { + Exist, + OpenAccess, + ReadAccess, + WriteAccess +}; + +} + +/** check if the file exist +*/ +static bool ifFileExist(const OUString & str) +{ + File testFile(str); + return (testFile.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None); +} + +/** check if the file can be written +*/ +static bool ifFileCanWrite(const OUString & str) +{ + // on Windows, the file has no write right, but can be written +#ifdef _WIN32 + bool bCheckResult = false; + OUString aUStr = str.copy(0); + if (isURL(str)) + osl::FileBase::getSystemPathFromFileURL(str, aUStr); + + OString aString = OUStringToOString(aUStr, RTL_TEXTENCODING_ASCII_US); + const char *path = aString.getStr(); + if ((_access(path, 2)) != -1) + bCheckResult = true; + // on UNX, just test if open success with osl_File_OpenFlag_Write +#else + File testFile(str); + bool bCheckResult = (testFile.open(osl_File_OpenFlag_Write) == osl::FileBase::E_None); +#endif + return bCheckResult; +} + +static bool checkDirectory(const OUString& str, oslCheckMode nCheckMode) +{ + OUString aUString; + DirectoryItem rItem; + osl::FileBase::RC rc; + bool bCheckResult= false; + + Directory aDir(str); + rc = aDir.open(); + + if ((rc != osl::FileBase::E_NOENT) && (rc != osl::FileBase::E_ACCES)) + { + switch (nCheckMode) + { + case oslCheckMode::Exist: + if (rc == ::osl::FileBase::E_None) + bCheckResult = true; + break; + case oslCheckMode::OpenAccess: + if (rc == osl::FileBase::E_None) + bCheckResult = true; + break; + case oslCheckMode::ReadAccess: + rc = aDir.getNextItem(rItem); + bCheckResult = (rc == osl::FileBase::E_None) || (rc == osl::FileBase::E_NOENT); + break; + case oslCheckMode::WriteAccess: + ((aUString += str) += aSlashURL) += aTmpName2; + if (Directory::create(aUString) == osl::FileBase::E_None) + { + bCheckResult = true; + rc = Directory::remove(aUString); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, rc); + } + else + { + bCheckResult = false; + } + break; + + default: + bCheckResult = false; + } + + rc = aDir.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, rc); + } + + return bCheckResult; +} + +/** construct error message +*/ +static OString outputError(const OString & returnVal, const OString & rightVal, const char * msg = "") +{ + if (returnVal == rightVal) + return OString(); + + OString aString = msg + + OString::Concat(": the returned value is '") + + returnVal + + "', but the value should be '" + + rightVal + + "'."; + return aString; +} + +#if (defined UNX) /* chmod() method is different in Windows */ +/** Change file mode, two version in UNIX and Windows;. +*/ +static void changeFileMode(OUString & filepath, sal_Int32 mode) +{ + OString aString; + OUString aUStr = filepath.copy(0); + + if (isURL(filepath)) + osl::FileBase::getSystemPathFromFileURL(filepath, aUStr); + + aString = OUStringToOString(aUStr, RTL_TEXTENCODING_ASCII_US); + int ret = chmod(aString.getStr(), mode); + CPPUNIT_ASSERT_EQUAL(0, ret); +} +#else +static void hideFile(const OUString& filepath) +{ + OUString aSysPath(filepath); + + if (isURL(filepath)) + osl::FileBase::getSystemPathFromFileURL(filepath, aSysPath); + + bool ret = SetFileAttributesW(o3tl::toW(aSysPath.getStr()), FILE_ATTRIBUTE_HIDDEN); + CPPUNIT_ASSERT(ret); +} +#endif + +#if 0 +#if defined UNX +static OUString getCurrentPID(); +#endif +#endif + +// Beginning of the test cases for osl::FileBase class + +namespace osl_FileBase +{ + // testing the method + // static inline RC getAbsoluteFileURL(const OUString& ustrBaseDirectoryURL, + // const OUString& ustrRelativeFileURL, + // OUString& ustrAbsoluteFileURL) + + class getAbsoluteFileURL : public CppUnit::TestFixture + { + public: + void check_getAbsoluteFileURL(OUString const& _suBaseURL, + OString const& _sRelativeURL, + osl::FileBase::RC _nAssumeError, + OUString const& _suAssumeResultStr); + + void getAbsoluteFileURL_001_1(); + void getAbsoluteFileURL_001_2(); + void getAbsoluteFileURL_001_3(); + void getAbsoluteFileURL_001_4(); + void getAbsoluteFileURL_001_5(); + void getAbsoluteFileURL_001_6(); + void getAbsoluteFileURL_001_7(); + void getAbsoluteFileURL_001_8(); + void getAbsoluteFileURL_002(); + void getAbsoluteFileURL_003(); + void getAbsoluteFileURL_004(); + + CPPUNIT_TEST_SUITE(getAbsoluteFileURL); + CPPUNIT_TEST(getAbsoluteFileURL_001_1); + CPPUNIT_TEST(getAbsoluteFileURL_001_2); + CPPUNIT_TEST(getAbsoluteFileURL_001_3); + CPPUNIT_TEST(getAbsoluteFileURL_001_4); + CPPUNIT_TEST(getAbsoluteFileURL_001_5); + CPPUNIT_TEST(getAbsoluteFileURL_001_6); + CPPUNIT_TEST(getAbsoluteFileURL_001_7); + CPPUNIT_TEST(getAbsoluteFileURL_001_8); + CPPUNIT_TEST(getAbsoluteFileURL_002); + CPPUNIT_TEST(getAbsoluteFileURL_003); + CPPUNIT_TEST(getAbsoluteFileURL_004); + CPPUNIT_TEST_SUITE_END(); + }; + + void getAbsoluteFileURL::check_getAbsoluteFileURL(OUString const& _suBaseURL, + OString const& _sRelativeURL, + osl::FileBase::RC _nAssumeError, + OUString const& _suAssumeResultStr) + { + OUString suRelativeURL = OStringToOUString(_sRelativeURL, RTL_TEXTENCODING_UTF8); + OString sBaseURL = OUStringToOString(_suBaseURL, RTL_TEXTENCODING_UTF8); + OUString suResultURL; + osl::FileBase::RC nError = osl::FileBase::getAbsoluteFileURL(_suBaseURL, suRelativeURL, suResultURL); + OString sResultURL = OUStringToOString(suResultURL, RTL_TEXTENCODING_UTF8); + OString sError = errorToString(nError); + printf("getAbsoluteFileURL('%s','%s') deliver absolute URL: '%s', error '%s'\n", + sBaseURL.getStr(), _sRelativeURL.getStr(),sResultURL.getStr(), sError.getStr()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Assumption is wrong: error number is wrong", _nAssumeError, nError); + + if (nError == osl::FileBase::E_None) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("Assumption is wrong: ResultURL is not equal to expected URL ", _suAssumeResultStr, suResultURL); + } + } + + void getAbsoluteFileURL::getAbsoluteFileURL_001_1() + { + OUString suAssume = aUserDirectoryURL + "/relative/file1"; + check_getAbsoluteFileURL(aUserDirectoryURL, "relative/file1"_ostr,osl::FileBase::E_None, suAssume); + } + + void getAbsoluteFileURL::getAbsoluteFileURL_001_2() + { + OUString suAssume = aUserDirectoryURL + "/relative/file2"; + check_getAbsoluteFileURL(aUserDirectoryURL, "relative/./file2"_ostr,osl::FileBase::E_None, suAssume); + } + + void getAbsoluteFileURL::getAbsoluteFileURL_001_3() + { + OUString suAssume = aUserDirectoryURL + "/file3"; + check_getAbsoluteFileURL(aUserDirectoryURL, "relative/../file3"_ostr,osl::FileBase::E_None, suAssume); + } + + void getAbsoluteFileURL::getAbsoluteFileURL_001_4() + { + OUString suAssume = aUserDirectoryURL + "/file4"; + check_getAbsoluteFileURL(aUserDirectoryURL, "././relative/../file4"_ostr,osl::FileBase::E_None, suAssume); + } + + void getAbsoluteFileURL::getAbsoluteFileURL_001_5() + { + OUString suAssume; + suAssume = aUserDirectoryURL + "/relative/"; + check_getAbsoluteFileURL(aUserDirectoryURL, "././relative/."_ostr,osl::FileBase::E_None, suAssume); + } + + void getAbsoluteFileURL::getAbsoluteFileURL_001_6() + { + OUString suAssume = aUserDirectoryURL + "/.relative"; + check_getAbsoluteFileURL(aUserDirectoryURL, "./.relative"_ostr,osl::FileBase::E_None, suAssume); + } + + void getAbsoluteFileURL::getAbsoluteFileURL_001_7() + { + OUString suAssume; + suAssume = aUserDirectoryURL + "/.a/"; + check_getAbsoluteFileURL(aUserDirectoryURL, "./.a/mydir/.."_ostr,osl::FileBase::E_None, suAssume); + } + + void getAbsoluteFileURL::getAbsoluteFileURL_001_8() + { + OUString suAssume = aUserDirectoryURL + "/tmp/ok"; + check_getAbsoluteFileURL(aUserDirectoryURL, "tmp//ok"_ostr,osl::FileBase::E_None, suAssume); + } + + void getAbsoluteFileURL::getAbsoluteFileURL_002() + { +#if 0 +#if (defined UNX) // Link is not defined in Windows + OUString aUStr_LnkFileSys(aTempDirectorySys), aUStr_SrcFileSys(aTempDirectorySys); + aUStr_LnkFileSys += aSlashURL + getCurrentPID() + "/link.file"; + aUStr_SrcFileSys += aSlashURL + getCurrentPID() + "/canonical.name"; + + OString strLinkFileName, strSrcFileName; + strLinkFileName = OUStringToOString(aUStr_LnkFileSys, RTL_TEXTENCODING_ASCII_US); + strSrcFileName = OUStringToOString(aUStr_SrcFileSys, RTL_TEXTENCODING_ASCII_US); + + createTestFile(aCanURL1); + sal_Int32 fd = symlink(strSrcFileName.getStr(), strLinkFileName.getStr()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), fd); + OString sLnkURL = OUStringToOString(aLnkURL1, RTL_TEXTENCODING_ASCII_US); + OUString suAssume = aUserDirectoryURL + "/canonical.name"; + check_getAbsoluteFileURL(aUserDirectoryURL, sLnkURL, osl::FileBase::E_None, suAssume); + deleteTestFile(aCanURL1); + fd = remove(strLinkFileName.getStr()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), fd); +#endif +#endif + } + + // please see line# 930 + void getAbsoluteFileURL::getAbsoluteFileURL_003() + { + } + + void getAbsoluteFileURL::getAbsoluteFileURL_004() + { + // create two level directories under $Temp/PID/ + OUString aUStrUpBase = aUserDirectoryURL + "/test1"; + createTestDirectory(aUStrUpBase); + OUString aUStrBase = aUserDirectoryURL + "/test1/dir1"; + createTestDirectory(aUStrBase); + + OUString suAssume = aUserDirectoryURL + "/mytestfile"; + check_getAbsoluteFileURL(aUStrBase, "../../mytestfile"_ostr , osl::FileBase::E_None, suAssume); + deleteTestDirectory(aUStrBase); + deleteTestDirectory(aUStrUpBase); + } + + // testing two methods: + // static inline RC getSystemPathFromFileURL(const OUString& ustrFileURL, + // OUString& ustrSystemPath) + // static RC getFileURLFromSystemPath(const OUString & ustrSystemPath, + // OUString & ustrFileURL); + + class SystemPath_FileURL : public CppUnit::TestFixture + { + public: + void getSystemPathFromFileURL_001_1(); + void getSystemPathFromFileURL_001_2(); + void getSystemPathFromFileURL_001_21(); + void getSystemPathFromFileURL_001_22(); + void getSystemPathFromFileURL_001_3(); + void getSystemPathFromFileURL_001_31(); + void getSystemPathFromFileURL_001_4(); + void getSystemPathFromFileURL_001_41(); + void getSystemPathFromFileURL_001_5(); + void getSystemPathFromFileURL_001_51(); + void getSystemPathFromFileURL_001_52(); + void getSystemPathFromFileURL_001_53(); + void getSystemPathFromFileURL_001_6(); + void getSystemPathFromFileURL_001_61(); + void getSystemPathFromFileURL_001_7(); + void getSystemPathFromFileURL_001_71(); + void getSystemPathFromFileURL_001_8(); + void getSystemPathFromFileURL_001_81(); + void getSystemPathFromFileURL_001_9(); + void getSystemPathFromFileURL_001_91(); + void getSystemPathFromFileURL_001_92(); + void getSystemPathFromFileURL_004(); + void getSystemPathFromFileURL_005(); + + // test case for getFileURLFromSystemPath + void getFileURLFromSystemPath_001(); + void getFileURLFromSystemPath_002(); + void getFileURLFromSystemPath_003(); + void getFileURLFromSystemPath_004(); + void getFileURLFromSystemPath_004_1(); + void getFileURLFromSystemPath_005(); + + CPPUNIT_TEST_SUITE(SystemPath_FileURL); + CPPUNIT_TEST(getSystemPathFromFileURL_001_1); + CPPUNIT_TEST(getSystemPathFromFileURL_001_2); + CPPUNIT_TEST(getSystemPathFromFileURL_001_21); + CPPUNIT_TEST(getSystemPathFromFileURL_001_22); + CPPUNIT_TEST(getSystemPathFromFileURL_001_3); + CPPUNIT_TEST(getSystemPathFromFileURL_001_31); + CPPUNIT_TEST(getSystemPathFromFileURL_001_4); + CPPUNIT_TEST(getSystemPathFromFileURL_001_41); + CPPUNIT_TEST(getSystemPathFromFileURL_001_5); + CPPUNIT_TEST(getSystemPathFromFileURL_001_51); + CPPUNIT_TEST(getSystemPathFromFileURL_001_52); + CPPUNIT_TEST(getSystemPathFromFileURL_001_53); + CPPUNIT_TEST(getSystemPathFromFileURL_001_6); + CPPUNIT_TEST(getSystemPathFromFileURL_001_61); + CPPUNIT_TEST(getSystemPathFromFileURL_001_7); + CPPUNIT_TEST(getSystemPathFromFileURL_001_71); + CPPUNIT_TEST(getSystemPathFromFileURL_001_8); + CPPUNIT_TEST(getSystemPathFromFileURL_001_81); + CPPUNIT_TEST(getSystemPathFromFileURL_001_9); + CPPUNIT_TEST(getSystemPathFromFileURL_001_91); + CPPUNIT_TEST(getSystemPathFromFileURL_001_92); + CPPUNIT_TEST(getSystemPathFromFileURL_004); + CPPUNIT_TEST(getSystemPathFromFileURL_005); + CPPUNIT_TEST(getFileURLFromSystemPath_001); + CPPUNIT_TEST(getFileURLFromSystemPath_002); + CPPUNIT_TEST(getFileURLFromSystemPath_003); + CPPUNIT_TEST(getFileURLFromSystemPath_004); + CPPUNIT_TEST(getFileURLFromSystemPath_004_1); + CPPUNIT_TEST(getFileURLFromSystemPath_005); + CPPUNIT_TEST_SUITE_END(); + + private: + void check_SystemPath_FileURL( + OString const& _sSource, + osl::FileBase::RC _nAssumeError, + OString const& _sAssumeResultStr, + bool bDirection = true); + + void checkWNTBehaviour_getSystemPathFromFileURL( + OString const& _sURL, + osl::FileBase::RC _nAssumeError, + OString const& _sWNTAssumeResultString); + + void checkUNXBehaviour_getSystemPathFromFileURL( + OString const& _sURL, + osl::FileBase::RC _nAssumeError, + OString const& _sUnixAssumeResultString); + + void checkWNTBehaviour_getFileURLFromSystemPath(OString const& _sSysPath, + osl::FileBase::RC _nAssumeError, + OString const& _sWNTAssumeResultString); + + void checkUNXBehaviour_getFileURLFromSystemPath( + OString const& _sSysPath, + osl::FileBase::RC _nAssumeError, + OString const& _sUnixAssumeResultString); + + }; + + // if bDirection==sal_True, check getSystemPathFromFileURL + // if bDirection==sal_False, check getFileURLFromSystemPath + void SystemPath_FileURL::check_SystemPath_FileURL( + OString const& _sSource, + osl::FileBase::RC _nAssumeError, + OString const& _sAssumeResultStr, + bool bDirection) + { + // PRE: URL as String + OUString suSource; + OUString suStr; + suSource = OStringToOUString(_sSource, RTL_TEXTENCODING_UTF8); + osl::FileBase::RC nError; + + if (bDirection) + nError = osl::FileBase::getSystemPathFromFileURL(suSource, suStr); + else + nError = osl::FileBase::getFileURLFromSystemPath(suSource, suStr); + + // if the given string is gt length 0, + // we check also this string + OString sStr = OUStringToOString(suStr, RTL_TEXTENCODING_UTF8); + OString sError = errorToString(nError); + + if (bDirection) + printf("getSystemPathFromFileURL('%s') deliver system path: '%s', error '%s'\n", + _sSource.getStr(), sStr.getStr(), sError.getStr()); + else + printf("getFileURLFromSystemPath('%s') deliver File URL: '%s', error '%s'\n", + _sSource.getStr(), sStr.getStr(), sError.getStr()); + + if (!_sAssumeResultStr.isEmpty()) + { + bool bStrAreEqual = _sAssumeResultStr == sStr; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Assumption is wrong", + _nAssumeError, nError); + CPPUNIT_ASSERT_MESSAGE("Assumption is wrong", + bStrAreEqual); + } + else + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("Assumption is wrong", _nAssumeError, nError); + } + } + + void SystemPath_FileURL::checkWNTBehaviour_getSystemPathFromFileURL( + OString const& _sURL, + osl::FileBase::RC _nAssumeError, + OString const& _sWNTAssumeResultString) + { +#if defined(_WIN32) + check_SystemPath_FileURL(_sURL, _nAssumeError, _sWNTAssumeResultString); +#else + (void)_sURL; + (void)_nAssumeError; + (void)_sWNTAssumeResultString; +#endif + } + + void SystemPath_FileURL::checkUNXBehaviour_getSystemPathFromFileURL( + OString const& _sURL, + osl::FileBase::RC _nAssumeError, + OString const& _sUnixAssumeResultString) + { +#if (defined UNX) + check_SystemPath_FileURL(_sURL, _nAssumeError, _sUnixAssumeResultString); +#else + (void)_sURL; + (void)_nAssumeError; + (void)_sUnixAssumeResultString; +#endif + } + + void SystemPath_FileURL::checkWNTBehaviour_getFileURLFromSystemPath( + OString const& _sSysPath, + osl::FileBase::RC _nAssumeError, + OString const& _sWNTAssumeResultString) + { +#if defined(_WIN32) + check_SystemPath_FileURL(_sSysPath, _nAssumeError, _sWNTAssumeResultString, false); +#else + (void)_sSysPath; + (void)_nAssumeError; + (void)_sWNTAssumeResultString; +#endif + } + + void SystemPath_FileURL::checkUNXBehaviour_getFileURLFromSystemPath( + OString const& _sSysPath, + osl::FileBase::RC _nAssumeError, + OString const& _sUnixAssumeResultString) + { +#if (defined UNX) + check_SystemPath_FileURL(_sSysPath, _nAssumeError, _sUnixAssumeResultString, false); +#else + (void)_sSysPath; + (void)_nAssumeError; + (void)_sUnixAssumeResultString; +#endif + } + + /** Test for getSystemPathFromFileURL() + this test is split into 2 different OS tests, + the first function checkUNXBehaviour... runs only on Unix based Systems, + the second only on windows based systems + the first parameter are a file URL where we want to get the system path of, + the second parameter is the assumed error of the osl_getSystemPathFromFileURL() function, + the third parameter is the assumed result string, the string will only test, if its length is greater than 0 + */ + + void SystemPath_FileURL::getSystemPathFromFileURL_001_1() + { + OString sURL(""_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_2() + { + OString sURL("/"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "\\"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_21() + { + /* From RFC3986, "2.2. Reserved Characters": + + "The purpose of reserved characters is to provide a set of delimiting + characters that are distinguishable from other data within a URI. + URIs that differ in the replacement of a reserved character with its + corresponding percent-encoded octet are not equivalent. Percent- + encoding a reserved character, or decoding a percent-encoded octet + that corresponds to a reserved character, will change how the URI is + interpreted by most applications. Thus, characters in the reserved + set are protected from normalization and are therefore safe to be + used by scheme-specific and producer-specific algorithms for + delimiting data subcomponents within a URI." + + In other words, %2F ("/") is NOT the same as /. + */ + OString sURL("%2F"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_22() + { + OString sURL("file:///tmp%2Fmydir"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_3() + { + OString sURL("a"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "a"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "a"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_31() + { + OString sURL("tmpname"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "tmpname"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "tmpname"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_4() + { + OString sURL("file://"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, ""_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_41() + { + OString sURL("file://localhost/tmp"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, ""_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_5() + { + OString sURL("file:///tmp"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/tmp"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_51() + { + OString sURL("file://c:/tmp"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_52() + { + OString sURL("file:///c:/tmp"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/c:/tmp"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "c:\\tmp"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_53() + { + OString sURL("file:///c|/tmp"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/c|/tmp"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "c:\\tmp"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_6() + { + OString sURL("file:///tmp/first"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/tmp/first"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_61() + { + OString sURL("file:///c:/tmp/first"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/c:/tmp/first"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "c:\\tmp\\first"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_7() + { + OString sURL("file:///tmp/../second"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/tmp/../second"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_71() + { + OString sURL("file:///c:/tmp/../second"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/c:/tmp/../second"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "c:\\tmp\\..\\second"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_8() + { + OString sURL("../tmp"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "../tmp"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "..\\tmp"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_81() + { +#if 0 + OString sURL("file://~/tmp"); + char* home_path; + home_path = getenv("HOME"); + OString expResult(home_path ? home_path : ""); + expResult += "/tmp"; + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, expResult); +#endif + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_9() + { + OString sURL("file:///tmp/first%20second"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/tmp/first second"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_91() + { + OString sURL("file:///c:/tmp/first%20second"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "/c:/tmp/first second"_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_None, "c:\\tmp\\first second"_ostr); + } + + void SystemPath_FileURL::getSystemPathFromFileURL_001_92() + { + OString sURL("ca@#;+.,$///78no%01ni..name"_ostr); + checkUNXBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + checkWNTBehaviour_getSystemPathFromFileURL(sURL, osl::FileBase::E_INVAL, ""_ostr); + } + + // normal legal case + void SystemPath_FileURL::getSystemPathFromFileURL_004() + { + OUString aUStr; + OUString aUNormalURL(aTmpName6); + OUString aUResultURL (aSysPath4); + osl::FileBase::RC nError = osl::FileBase::getSystemPathFromFileURL(aUNormalURL, aUStr); + + bool bOk = compareFileName(aUStr, aUResultURL); + + OString sError = + "test for getSystemPathFromFileURL(' " + + OUStringToOString(aUNormalURL, RTL_TEXTENCODING_ASCII_US) + + " ') function:use an absolute file URL, " + + outputError(OUStringToOString(aUStr, RTL_TEXTENCODING_ASCII_US), + OUStringToOString(aUResultURL, RTL_TEXTENCODING_ASCII_US)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sError.getStr(), osl::FileBase::E_None, nError); + CPPUNIT_ASSERT_MESSAGE(sError.getStr(), bOk); + + } + + // CJK characters case + void SystemPath_FileURL::getSystemPathFromFileURL_005() + { + OUString aUStr; + createTestDirectory(aTmpName10); + OUString aUNormalURL(aTmpName10); + OUString aUResultURL (aSysPath5); + + osl::FileBase::RC nError = osl::FileBase::getSystemPathFromFileURL(aUNormalURL, aUStr); + + bool bOk = compareFileName(aUStr, aUResultURL); + + OString sError = + "test for getSystemPathFromFileURL(' " + + OUStringToOString(aUNormalURL, RTL_TEXTENCODING_ASCII_US) + + " ') function:use a CJK coded absolute URL, " + + outputError(OUStringToOString(aUStr, RTL_TEXTENCODING_ASCII_US), + OUStringToOString(aUResultURL, RTL_TEXTENCODING_ASCII_US)); + deleteTestDirectory(aTmpName10); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sError.getStr(), osl::FileBase::E_None, nError); + CPPUNIT_ASSERT_MESSAGE(sError.getStr(), bOk); + } + + void SystemPath_FileURL::getFileURLFromSystemPath_001() + { + OString sSysPath("~/tmp"_ostr); + char* home_path; + home_path = getenv("HOME"); + OString expResult(home_path ? home_path : ""); + expResult = "file://"+ expResult + "/tmp"; + checkUNXBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_None, expResult); + checkWNTBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_None, "~/tmp"_ostr); + } + + void SystemPath_FileURL::getFileURLFromSystemPath_002() + { + OString sSysPath("c:/tmp"_ostr); + checkUNXBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_None, "c:/tmp"_ostr); + checkWNTBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_None, "file:///c:/tmp"_ostr); + } + + void SystemPath_FileURL::getFileURLFromSystemPath_003() + { + OString sSysPath("file:///temp"_ostr); + checkUNXBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_INVAL, ""_ostr); + checkWNTBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getFileURLFromSystemPath_004() + { + OString sSysPath("//tmp//first start"_ostr); + checkUNXBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_None, "file:///tmp/first%20start"_ostr); + checkWNTBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getFileURLFromSystemPath_004_1() + { + OString sSysPath("/tmp///first start"_ostr); + checkUNXBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_None, "file:///tmp/first%20start"_ostr); + checkWNTBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_INVAL, ""_ostr); + } + + void SystemPath_FileURL::getFileURLFromSystemPath_005() + { + OString sSysPath(""_ostr); + checkUNXBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_INVAL, ""_ostr); + checkWNTBehaviour_getFileURLFromSystemPath(sSysPath, osl::FileBase::E_INVAL, ""_ostr); + } + + // testing the method + // static inline RC searchFileURL( const OUString& ustrFileName, + // const OUString& ustrSearchPath, + // OUString& ustrFileURL) + + class searchFileURL : public CppUnit::TestFixture + { + private: + OUString aUStr; + + public: + void searchFileURL_001() + { + /* search file is passed by system filename */ + auto nError1 = osl::FileBase::searchFileURL(aTmpName1, aUserDirectorySys, aUStr); + /* search file is passed by full qualified file URL */ + auto nError2 = osl::FileBase::searchFileURL(aCanURL1, aUserDirectorySys, aUStr); + /* search file is passed by relative file path */ + auto nError3 = osl::FileBase::searchFileURL(aRelURL4, aUserDirectorySys, aUStr); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: system filename/URL filename/relative path, system directory, searched files that is not exist, but it reply invalid error, did not pass in (W32) ", + osl::FileBase::E_NOENT, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: system filename/URL filename/relative path, system directory, searched files that is not exist, but it reply invalid error, did not pass in (W32) ", + osl::FileBase::E_NOENT, nError2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: system filename/URL filename/relative path, system directory, searched files that is not exist, but it reply invalid error, did not pass in (W32) ", + osl::FileBase::E_NOENT, nError3); + } + + void searchFileURL_002() + { +#ifndef UNX + /* search file is passed by system filename */ + OUString strRootSys = INetURLObject(aTempDirectoryURL).GetLastName(); + auto nError1 = osl::FileBase::searchFileURL(aTempDirectorySys, strRootSys, aUStr); + bool bOk1 = compareFileName(aUStr, aTempDirectoryURL); + /* search file is passed by full qualified file URL */ + auto nError2 = osl::FileBase::searchFileURL(aTempDirectoryURL, strRootSys, aUStr); + bool bOk2 = compareFileName(aUStr, aTempDirectoryURL); +#ifndef _WIN32 + /* search file is passed by relative file path */ + auto nError3 = osl::FileBase::searchFileURL(aRelURL5, strRootSys, aUStr); + bool bOk3 = compareFileName(aUStr, aTempDirectoryURL); +#endif + /* search file is passed by an exist file */ + createTestFile(aCanURL1); + auto nError4 = osl::FileBase::searchFileURL(aCanURL4, aUserDirectorySys, aUStr); + bool bOk4 = compareFileName(aUStr, aCanURL1); + deleteTestFile(aCanURL1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: system filename, system directory, searched file already exist.", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: URL filename, system directory, searched file already exist.", + osl::FileBase::E_None, nError2); +#ifndef _WIN32 + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: relative path, system directory, searched file already exist.", + osl::FileBase::E_None, nError3); +#endif + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: system filename/URL filename/relative path, system directory, searched file already exist.", + osl::FileBase::E_None, nError4); + CPPUNIT_ASSERT_MESSAGE("test for searchFileURL function: system filename, system directory, searched file already exist.", + bOk1); + CPPUNIT_ASSERT_MESSAGE("test for searchFileURL function: URL filename, system directory, searched file already exist.", + bOk2); +#ifndef _WIN32 + CPPUNIT_ASSERT_MESSAGE("test for searchFileURL function: relative path, system directory, searched file already exist.", + bOk3); +#endif + CPPUNIT_ASSERT_MESSAGE("test for searchFileURL function: system filename/URL filename/relative path, system directory, searched file already exist.", + bOk4); +#endif + } + + void searchFileURL_003() + { + OUString aSystemPathList(aRootSys + PATH_LIST_DELIMITER + aTempDirectorySys + PATH_LIST_DELIMITER + aRootSys + "system/path"); + auto nError1 = osl::FileBase::searchFileURL(aUserDirectoryURL, aSystemPathList, aUStr); + bool bOk = compareFileName(aUStr, aUserDirectoryURL); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: search directory is a list of system paths", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_MESSAGE("test for searchFileURL function: search directory is a list of system paths", + bOk); + } + + void searchFileURL_004() + { + OUString aSystemPathList(aRootSys + PATH_LIST_DELIMITER + aTempDirectorySys + PATH_LIST_DELIMITER + aRootSys + "system/path/../name"); + auto nError1 = osl::FileBase::searchFileURL(aUserDirectoryURL, aSystemPathList, aUStr); + bool bOk = compareFileName(aUStr, aUserDirectoryURL); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: search directory is a list of system paths", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_MESSAGE("test for searchFileURL function: search directory is a list of system paths", + bOk); + } + + void searchFileURL_005() + { + auto nError1 = osl::FileBase::searchFileURL(aUserDirectoryURL, aNullURL, aUStr); + bool bOk = compareFileName(aUStr, aUserDirectoryURL); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for searchFileURL function: search directory is NULL", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_MESSAGE("test for searchFileURL function: search directory is NULL", + bOk); + } + + CPPUNIT_TEST_SUITE(searchFileURL); + CPPUNIT_TEST(searchFileURL_001); + CPPUNIT_TEST(searchFileURL_002); + CPPUNIT_TEST(searchFileURL_003); + CPPUNIT_TEST(searchFileURL_004); + CPPUNIT_TEST(searchFileURL_005); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // static inline RC getTempDirURL(OUString& ustrTempDirURL) + + class getTempDirURL : public CppUnit::TestFixture + { + private: + OUString aUStr; + + public: + void setUp() override + { + osl::FileBase::RC nError = osl::FileBase::getTempDirURL(aUStr); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getTempDirURL function: execution", + osl::FileBase::E_None, nError); + } + + void getTempDirURL_002() + { + CPPUNIT_ASSERT_MESSAGE("test for getTempDirURL function: test for open and write access rights", + checkDirectory(aUStr, oslCheckMode::OpenAccess)); + CPPUNIT_ASSERT_MESSAGE("test for getTempDirURL function: test for open and write access rights", + checkDirectory(aUStr, oslCheckMode::ReadAccess)); + CPPUNIT_ASSERT_MESSAGE("test for getTempDirURL function: test for open and write access rights", + checkDirectory(aUStr, oslCheckMode::WriteAccess)); + } + + CPPUNIT_TEST_SUITE(getTempDirURL); + CPPUNIT_TEST(getTempDirURL_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // static inline RC createTempFile(OUString* pustrDirectoryURL, + // oslFileHandle* pHandle, + // OUString* pustrTempFileURL) + + class createTempFile : public CppUnit::TestFixture + { + private: + std::unique_ptr<oslFileHandle> pHandle; + std::unique_ptr<OUString> pUStr_DirURL; + std::unique_ptr<OUString> pUStr_FileURL; + + public: + void setUp() override + { + pHandle.reset(new oslFileHandle()); + pUStr_DirURL.reset(new OUString(aUserDirectoryURL)); + pUStr_FileURL.reset(new OUString()); + } + + void tearDown() override + { + pUStr_DirURL.reset(); + pUStr_FileURL.reset(); + pHandle.reset(); + } + + void createTempFile_001() + { + auto nError1 = osl::FileBase::createTempFile(pUStr_DirURL.get(), pHandle.get(), pUStr_FileURL.get()); + File testFile(*pUStr_FileURL); + auto nError2 = testFile.open(osl_File_OpenFlag_Create); + + if (nError2 == osl::FileBase::E_EXIST) + { + osl_closeFile(*pHandle); + deleteTestFile(*pUStr_FileURL); + } + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for createTempFile function: create temp file and test the existence", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_MESSAGE("test for createTempFile function: create temp file and test the existence", + (pHandle != nullptr)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for createTempFile function: create temp file and test the existence", + osl::FileBase::E_EXIST, nError2); + } + + void createTempFile_002() + { + bool bOK = false; + auto nError1 = osl::FileBase::createTempFile(pUStr_DirURL.get(), pHandle.get(), pUStr_FileURL.get()); + File testFile(*pUStr_FileURL); + auto nError2 = testFile.open(osl_File_OpenFlag_Create); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("createTempFile function: create a temp file, but it does not exist", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_MESSAGE("createTempFile function: create a temp file, but it does not exist", + (pHandle != nullptr)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("createTempFile function: create a temp file, but it does not exist", + osl::FileBase::E_EXIST, nError2); + + // check file if have the write permission + if (nError2 == osl::FileBase::E_EXIST) + { + bOK = ifFileCanWrite(*pUStr_FileURL); + osl_closeFile(*pHandle); + deleteTestFile(*pUStr_FileURL); + } + + CPPUNIT_ASSERT_MESSAGE("test for open and write access rights, in (W32), it did not have write access right, but it should be writable.", + bOK); + } + + void createTempFile_003() + { + auto nError1 = osl::FileBase::createTempFile(pUStr_DirURL.get(), pHandle.get(), nullptr); + // the temp file will be removed when return from createTempFile + bool bOK = (pHandle != nullptr && nError1 == osl::FileBase::E_None); + if (bOK) + osl_closeFile(*pHandle); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for createTempFile function: set pUStrFileURL to 0 to let it remove the file after call.", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_MESSAGE("test for createTempFile function: set pUStrFileURL to 0 to let it remove the file after call.", + bOK); + } + + void createTempFile_004() + { + auto nError1 = osl::FileBase::createTempFile(pUStr_DirURL.get(), nullptr, pUStr_FileURL.get()); + bool bOK = (pUStr_FileURL != nullptr); + CPPUNIT_ASSERT(bOK); + File testFile(*pUStr_FileURL); + auto nError2 = testFile.open(osl_File_OpenFlag_Create); + deleteTestFile(*pUStr_FileURL); + CPPUNIT_ASSERT_EQUAL_MESSAGE("createTempFile function: create a temp file, but it does not exist", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("createTempFile function: create a temp file, but it does not exist", + osl::FileBase::E_EXIST, nError2); + CPPUNIT_ASSERT_MESSAGE("createTempFile function: create a temp file, but it does not exist", + bOK); + + } + + CPPUNIT_TEST_SUITE(createTempFile); + CPPUNIT_TEST(createTempFile_001); + CPPUNIT_TEST(createTempFile_002); + CPPUNIT_TEST(createTempFile_003); + CPPUNIT_TEST(createTempFile_004); + CPPUNIT_TEST_SUITE_END(); + }; + + // FIXME: remove the _disabled to enable: + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileBase::getAbsoluteFileURL, "osl_osl::FileBase"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileBase::SystemPath_FileURL, "osl_osl::FileBase"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileBase::searchFileURL, "osl_osl::FileBase"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileBase::getTempDirURL, "osl_osl::FileBase"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileBase::createTempFile, "osl_osl::FileBase"); + + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_osl::FileBase"); +} + +namespace osl_FileStatus +{ + // testing the method + // FileStatus(sal_uInt32 nMask): _nMask(nMask) + class ctors : public CppUnit::TestFixture + { + private: + OUString aUStr; + DirectoryItem rItem; + + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + Directory aDir(aTmpName3); + auto nError1 = aDir.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = aDir.getNextItem(rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + aDir.close(); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + void ctors_001() + { + FileStatus rFileStatus(osl_FileStatus_Mask_All); + auto nError1 = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + aUStr = rFileStatus.getFileName(); + + CPPUNIT_ASSERT_MESSAGE("test for ctors function: mask all and see the file name", + compareFileName(aUStr, aTmpName2)); + } + + void ctors_002() + { + FileStatus rFileStatus(0); + auto nError1 = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + aUStr = rFileStatus.getFileName(); + + CPPUNIT_ASSERT_MESSAGE("test for ctors function: mask is empty", + compareFileName(aUStr, aNullURL)); + } + + CPPUNIT_TEST_SUITE(ctors); + CPPUNIT_TEST(ctors_001); + CPPUNIT_TEST(ctors_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline sal_Bool isValid(sal_uInt32 nMask) const + + class isValid : public CppUnit::TestFixture + { + private: + std::unique_ptr<Directory> pDir; + DirectoryItem rItem_file, rItem_link; + + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + pDir.reset(new Directory(aTmpName3)); + osl::FileBase::RC nError1 = pDir->open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = pDir->getNextItem(rItem_file, 1); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + osl::FileBase::RC nError1 = pDir->close(); + pDir.reset(); + CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError1).getStr(), osl::FileBase::E_None, nError1); + + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + void isValid_001() + { + sal_uInt32 mask = 0; + FileStatus rFileStatus(mask); + osl::FileBase::RC nError1 = rItem_file.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + bool bOk = rFileStatus.isValid(mask); + + CPPUNIT_ASSERT_MESSAGE("test for isValid function: no fields specified", bOk); + } + + void check_FileStatus(FileStatus const& _aStatus) + { + OString sStat; + if (_aStatus.isValid(osl_FileStatus_Mask_Type)) + sStat += "type "; + if (_aStatus.isValid(osl_FileStatus_Mask_Attributes)) + sStat += "attributes "; + if (_aStatus.isValid(osl_FileStatus_Mask_CreationTime)) + sStat += "ctime "; + if (_aStatus.isValid(osl_FileStatus_Mask_AccessTime)) + sStat += "atime "; + if (_aStatus.isValid(osl_FileStatus_Mask_ModifyTime)) + sStat += "mtime "; + if (_aStatus.isValid(osl_FileStatus_Mask_FileSize)) + sStat += "filesize "; + if (_aStatus.isValid(osl_FileStatus_Mask_FileName)) + sStat += "filename "; + if (_aStatus.isValid(osl_FileStatus_Mask_FileURL)) + sStat += "fileurl "; + printf("mask: %s\n", sStat.getStr()); + } + + void isValid_002() + { + createTestFile(aTmpName6); + sal_uInt32 mask_file = osl_FileStatus_Mask_Type | + osl_FileStatus_Mask_Attributes | + osl_FileStatus_Mask_CreationTime | + osl_FileStatus_Mask_AccessTime | + osl_FileStatus_Mask_ModifyTime | + osl_FileStatus_Mask_FileSize | + osl_FileStatus_Mask_FileName | + osl_FileStatus_Mask_FileURL; + + FileStatus rFileStatus(mask_file); + DirectoryItem::get(aTmpName6, rItem_file); + osl::FileBase::RC nError1 = rItem_file.getFileStatus(rFileStatus); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError1).getStr(), osl::FileBase::E_None, nError1); + + check_FileStatus(rFileStatus); + deleteTestFile(aTmpName6); + + } + + /** Check if is a valid linked file. + + Link is not defined in Windows, and on Linux, we can not get the directory item of the linked file. + We have to defer to filesystems, normal filesystems support links (EXT2, ...), castrated filesystems + don't have links (FAT, FAT32) and Windows NT NTFS support links, but the Windows API doesn't :-( + */ + void isValid_003() + { +#if 0 +#if defined (UNX) + sal_Int32 fd; + + OUString aUStr_LnkFileSys(aTempDirectorySys), aUStr_SrcFileSys(aTempDirectorySys); + aUStr_LnkFileSys += aSlashURL + getCurrentPID() + "/tmpdir/link.file"; + aUStr_SrcFileSys += aSlashURL + getCurrentPID() + "/tmpdir/tmpname"; + + OString strLinkFileName; + OString strSrcFileName; + strLinkFileName = OUStringToOString(aUStr_LnkFileSys, RTL_TEXTENCODING_ASCII_US); + strSrcFileName = OUStringToOString(aUStr_SrcFileSys, RTL_TEXTENCODING_ASCII_US); + + // create a link file and link it to file "/tmp/PID/tmpdir/tmpname" + fd = symlink(strSrcFileName.getStr(), strLinkFileName.getStr()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), fd); + + // testDirectory is "/tmp/PID/tmpdir/" + Directory testDirectory(aTmpName3); + testDirectory.open(); + OUString aFileName ("link.file"); + bool bOk = false; + while (true) + { + osl::FileBase::RC nError1 = testDirectory.getNextItem(rItem_link, 4); + + if (nError1 == osl::FileBase::E_None) + { + sal_uInt32 mask_link = osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_LinkTargetURL; + FileStatus rFileStatus(mask_link); + rItem_link.getFileStatus(rFileStatus); + + if (compareFileName(rFileStatus.getFileName(), aFileName)) + { + if (rFileStatus.isValid(osl_FileStatus_Mask_LinkTargetURL)) + { + bOk = true; + break; + } + } + } + else + { + break; + } + }; + + fd = remove(strLinkFileName.getStr()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), fd); + + CPPUNIT_ASSERT_MESSAGE("test for isValid function: link file, check for LinkTargetURL", bOk); +#endif +#endif + } + + void isValid_004() + { + sal_uInt32 mask_file_all = osl_FileStatus_Mask_All; + FileStatus rFileStatus_all(mask_file_all); + osl::FileBase::RC nError1 = rItem_file.getFileStatus(rFileStatus_all); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + check_FileStatus(rFileStatus_all); + + sal_uInt32 mask_file_val = osl_FileStatus_Mask_Validate; + FileStatus rFileStatus_val(mask_file_val); + nError1 = rItem_file.getFileStatus(rFileStatus_val); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + check_FileStatus(rFileStatus_val); + } + + CPPUNIT_TEST_SUITE(isValid); + CPPUNIT_TEST(isValid_001); + CPPUNIT_TEST(isValid_002); + CPPUNIT_TEST(isValid_003); + CPPUNIT_TEST(isValid_004); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline Type getFileType() const + + class getFileType : public CppUnit::TestFixture + { + private: + DirectoryItem m_aItem_1, m_aItem_2, m_aVolumeItem, m_aFifoItem; + DirectoryItem m_aLinkItem, m_aSocketItem, m_aSpecialItem; + + public: + void setUp() override + { + // create a tempfile: $TEMP/tmpdir/tmpname. + // a tempdirectory: $TEMP/tmpdir/tmpdir. + // use $ROOT/staroffice as volume ---> use dev/fd as volume. + // and get their directory item. + createTestDirectory(aTmpName3); + createTestFile(aTmpName3, aTmpName2); + createTestDirectory(aTmpName3, aTmpName1); + + std::unique_ptr<Directory> xDir(new Directory(aTmpName3)); + auto nError1 = xDir->open(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("open aTmpName3 failed!", osl::FileBase::E_None, nError1); + // getNextItem can not assure which item retrieved + nError1 = xDir->getNextItem(m_aItem_1, 1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("get first item failed!", osl::FileBase::E_None, nError1); + + nError1 = xDir->getNextItem(m_aItem_2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("get second item failed!", osl::FileBase::E_None, nError1); + xDir->close(); + // FIXME mindy: failed on my RH9, so removed temporarily + // nError1 = DirectoryItem::get(aVolURL2, m_aVolumeItem); + // CPPUNIT_ASSERT_MESSAGE("get volume item failed!", osl::FileBase::E_None == nError1); + } + + void tearDown() override + { + // remove all in $TEMP/tmpdir. + deleteTestDirectory(aTmpName3, aTmpName1); + deleteTestFile(aTmpName3, aTmpName2); + deleteTestDirectory(aTmpName3); + } + + void getFileType_001() + { + FileStatus rFileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName); + auto nError1 = m_aItem_1.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL_MESSAGE("getFileStatus failed", osl::FileBase::E_None, nError1); + + check_FileType(rFileStatus); + } + + void check_FileType(osl::FileStatus const& _rFileStatus) + { + if (_rFileStatus.isValid(osl_FileStatus_Mask_FileName)) + { + OUString suFilename = _rFileStatus.getFileName(); + + if (_rFileStatus.isValid(osl_FileStatus_Mask_Type)) + { + osl::FileStatus::Type eType = _rFileStatus.getFileType(); + bool bOK = false; + + if (compareFileName(suFilename, aTmpName2)) + bOK = (eType == osl::FileStatus::Regular); + + if (compareFileName(suFilename, aTmpName1)) + bOK = (eType == FileStatus::Directory); + + CPPUNIT_ASSERT_MESSAGE("test for getFileType function: ", bOK); + } + } + // LLA: it's not a bug, if a FileStatus not exist, so no else + } + + void getFileType_002() + { + FileStatus rFileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName); + auto nError1 = m_aItem_2.getFileStatus(rFileStatus); + + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + check_FileType(rFileStatus); + } + + void getFileType_003() + { + } + + void getFileType_007() + { +#if defined(__sun) // Special file is different in Windows + auto nError1 = DirectoryItem::get(aTypeURL2, m_aSpecialItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // check for File type + FileStatus rFileStatus(osl_FileStatus_Mask_Type); + nError1 = m_aSpecialItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + if (rFileStatus.isValid(osl_FileStatus_Mask_Type)) + { + osl::FileStatus::Type eType = rFileStatus.getFileType(); + + CPPUNIT_ASSERT_MESSAGE("test for getFileType function: Special, Solaris version ", + (eType == FileStatus::Special)); + } +#endif + } + + CPPUNIT_TEST_SUITE(getFileType); + CPPUNIT_TEST(getFileType_001); + CPPUNIT_TEST(getFileType_002); + CPPUNIT_TEST(getFileType_003); + CPPUNIT_TEST(getFileType_007); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline sal_uInt64 getAttributes() const + + class getAttributes : public CppUnit::TestFixture + { + private: + OUString aTypeURL, aTypeURL_Hid; + DirectoryItem rItem, rItem_hidden; + + public: + void setUp() override + { + aTypeURL = aUserDirectoryURL.copy(0); + concatURL(aTypeURL, aTmpName2); + createTestFile(aTypeURL); + osl::FileBase::RC nError = DirectoryItem::get(aTypeURL, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + aTypeURL_Hid = aUserDirectoryURL.copy(0); + concatURL(aTypeURL_Hid, aHidURL1); + createTestFile(aTypeURL_Hid); +#ifdef _WIN32 + hideFile(aTypeURL_Hid); +#endif + nError = DirectoryItem::get(aTypeURL_Hid, rItem_hidden); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + } + + void tearDown() override + { + deleteTestFile(aTypeURL); + deleteTestFile(aTypeURL_Hid); + } + +#if (defined UNX) +// windows only has 3 file attributes: normal, readonly and hidden + void getAttributes_001() + { + changeFileMode(aTypeURL, S_IRUSR | S_IRGRP | S_IROTH); + + FileStatus rFileStatus(osl_FileStatus_Mask_Attributes); + osl::FileBase::RC nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + if (geteuid() == 0) // as root, access(W_OK) may be true despite mode + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getAttributes function: (not ReadOnly,) GrpRead, OwnRead, OthRead(UNX version) ", + static_cast<sal_uInt64>(osl_File_Attribute_GrpRead | osl_File_Attribute_OwnRead | osl_File_Attribute_OthRead), + rFileStatus.getAttributes()); + } + else + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getAttributes function: ReadOnly, GrpRead, OwnRead, OthRead(UNX version) ", + static_cast<sal_uInt64>(osl_File_Attribute_ReadOnly | osl_File_Attribute_GrpRead | osl_File_Attribute_OwnRead | osl_File_Attribute_OthRead), + rFileStatus.getAttributes()); + } + } +#else // Windows version + void getAttributes_001() + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getAttributes function: ReadOnly, GrpRead, OwnRead, OthRead(Windows version)", + 1, 1); + } +#endif + + void getAttributes_002() + { +#if (defined UNX) + changeFileMode(aTypeURL, S_IXUSR | S_IXGRP | S_IXOTH); + + FileStatus rFileStatus(osl_FileStatus_Mask_Attributes); + osl::FileBase::RC nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + if (geteuid() == 0) // as root, access(W_OK) may be true despite mode + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getAttributes function: Executable, GrpExe, OwnExe, OthExe, the result is (not Readonly,) Executable, GrpExe, OwnExe, OthExe, it partly not pass(Solaris version)", + static_cast<sal_uInt64>(osl_File_Attribute_Executable | osl_File_Attribute_GrpExe | osl_File_Attribute_OwnExe | osl_File_Attribute_OthExe), + rFileStatus.getAttributes()); + } + else + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getAttributes function: Executable, GrpExe, OwnExe, OthExe, the result is Readonly, Executable, GrpExe, OwnExe, OthExe, it partly not pass(Solaris version)", + static_cast<sal_uInt64>(osl_File_Attribute_ReadOnly | osl_File_Attribute_Executable | osl_File_Attribute_GrpExe | osl_File_Attribute_OwnExe | osl_File_Attribute_OthExe), + rFileStatus.getAttributes()); + } +#endif + } + +#if (defined UNX) + void getAttributes_003() + { + changeFileMode(aTypeURL, S_IWUSR | S_IWGRP | S_IWOTH); + + FileStatus rFileStatus(osl_FileStatus_Mask_Attributes); + osl::FileBase::RC nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getAttributes function: GrpWrite, OwnWrite, OthWrite(Solaris version)", + static_cast<sal_uInt64>(osl_File_Attribute_GrpWrite | osl_File_Attribute_OwnWrite | osl_File_Attribute_OthWrite), + rFileStatus.getAttributes()); + } +#else // Windows version + void getAttributes_003() + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getAttributes function: GrpWrite, OwnWrite, OthWrite(Windows version)", + 1, 1); + } +#endif + + void getAttributes_004() + { + sal_Int32 test_Attributes = osl_File_Attribute_Hidden; + FileStatus rFileStatus(osl_FileStatus_Mask_Attributes); + osl::FileBase::RC nError = rItem_hidden.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + test_Attributes &= rFileStatus.getAttributes(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getAttributes function: Hidden files", + static_cast<sal_Int32>(osl_File_Attribute_Hidden), test_Attributes); + } + + CPPUNIT_TEST_SUITE(getAttributes); + CPPUNIT_TEST(getAttributes_001); + CPPUNIT_TEST(getAttributes_002); + CPPUNIT_TEST(getAttributes_003); + CPPUNIT_TEST(getAttributes_004); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline TimeValue getAccessTime() const + + class getAccessTime : public CppUnit::TestFixture + { + private: + OUString aTypeURL; + DirectoryItem rItem; + + public: + void setUp() override + { + aTypeURL = aUserDirectoryURL.copy(0); + concatURL(aTypeURL, aTmpName2); + createTestFile(aTypeURL); + osl::FileBase::RC nError = DirectoryItem::get(aTypeURL, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + } + + void tearDown() override + { + deleteTestFile(aTypeURL); + } + + void getAccessTime_001() + { + TimeValue *pTV_current = nullptr; + CPPUNIT_ASSERT((pTV_current = static_cast<TimeValue*>(malloc(sizeof(TimeValue)))) != nullptr); + TimeValue *pTV_access = nullptr; + CPPUNIT_ASSERT((pTV_access = static_cast<TimeValue*>(malloc(sizeof(TimeValue)))) != nullptr); + + FileStatus rFileStatus(osl_FileStatus_Mask_AccessTime); + osl::FileBase::RC nError = rItem.getFileStatus(rFileStatus); + bool bOk = osl_getSystemTime(pTV_current); + CPPUNIT_ASSERT(bOk); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + *pTV_access = rFileStatus.getAccessTime(); + + bool bOK = t_compareTime(pTV_access, pTV_current, delta); + free(pTV_current); + free(pTV_access); + + CPPUNIT_ASSERT_MESSAGE("test for getAccessTime function: This test turns out that UNX precision is no more than 1 sec, don't know how to test this function, in Windows test, it lost hour min sec, only have date time. ", + bOK); + } + + CPPUNIT_TEST_SUITE(getAccessTime); + CPPUNIT_TEST(getAccessTime_001); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline TimeValue getModifyTime() const + + class getModifyTime : public CppUnit::TestFixture + { + private: + OUString aTypeURL; + DirectoryItem rItem; + + public: + void getModifyTime_001() + { + TimeValue *pTV_current = nullptr; + CPPUNIT_ASSERT((pTV_current = static_cast<TimeValue*>(malloc(sizeof(TimeValue)))) != nullptr); + + // create file + aTypeURL = aUserDirectoryURL.copy(0); + concatURL(aTypeURL, aTmpName2); + createTestFile(aTypeURL); + + // get current time + bool bOk = osl_getSystemTime(pTV_current); + CPPUNIT_ASSERT(bOk); + + // get instance item and filestatus + osl::FileBase::RC nError = DirectoryItem::get(aTypeURL, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + FileStatus rFileStatus(osl_FileStatus_Mask_ModifyTime); + nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + // get modify time + TimeValue* pTV_modify = nullptr; + CPPUNIT_ASSERT((pTV_modify = static_cast<TimeValue*>(malloc(sizeof(TimeValue)))) != nullptr); + *pTV_modify = rFileStatus.getModifyTime(); + + bool bOK = t_compareTime(pTV_modify, pTV_current, delta); + // delete file + deleteTestFile(aTypeURL); + free(pTV_current); + free(pTV_modify); + + CPPUNIT_ASSERT_MESSAGE("test for getModifyTime function: This test turns out that UNX precision is no more than 1 sec, don't know how to improve this function. ", + bOK); + } + + CPPUNIT_TEST_SUITE(getModifyTime); + CPPUNIT_TEST(getModifyTime_001); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline sal_uInt64 getFileSize() const + + class getFileSize : public CppUnit::TestFixture + { + private: + OUString aTypeURL; + DirectoryItem rItem; + + public: + void setUp() override + { + aTypeURL = aUserDirectoryURL.copy(0); + concatURL(aTypeURL, aTmpName2); + createTestFile(aTypeURL); + osl::FileBase::RC nError = DirectoryItem::get(aTypeURL, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + } + + void tearDown() override + { + deleteTestFile(aTypeURL); + } + + void getFileSize_001() + { + FileStatus rFileStatus(osl_FileStatus_Mask_FileSize); + osl::FileBase::RC nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + sal_uInt64 uFileSize = rFileStatus.getFileSize(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getFileSize function: empty file ", + static_cast<sal_uInt64>(0), uFileSize); + } + + void getFileSize_002() + { + File testfile(aTypeURL); + osl::FileBase::RC nError = testfile.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Read); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + nError = testfile.setSize(TEST_FILE_SIZE); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + nError = DirectoryItem::get(aTypeURL, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + FileStatus rFileStatus(osl_FileStatus_Mask_FileSize); + nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + sal_uInt64 uFileSize = rFileStatus.getFileSize(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getFileSize function: file with size of TEST_FILE_SIZE, did not pass in (W32). ", + static_cast<sal_uInt64>(TEST_FILE_SIZE), uFileSize); + } + + CPPUNIT_TEST_SUITE(getFileSize); + CPPUNIT_TEST(getFileSize_001); + CPPUNIT_TEST(getFileSize_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline OUString getFileName() const + + class getFileName : public CppUnit::TestFixture + { + private: + OUString aTypeURL; + DirectoryItem rItem; + + public: + void setUp() override + { + aTypeURL = aUserDirectoryURL.copy(0); + concatURL(aTypeURL, aTmpName2); + createTestFile(aTypeURL); + osl::FileBase::RC nError = DirectoryItem::get(aTypeURL, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + } + + void tearDown() override + { + deleteTestFile(aTypeURL); + } + + + void getFileName_001() + { + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + osl::FileBase::RC nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + OUString aFileName = rFileStatus.getFileName(); + + CPPUNIT_ASSERT_MESSAGE("test for getFileName function: name compare with specify", + compareFileName(aFileName, aTmpName2)); + } + + CPPUNIT_TEST_SUITE(getFileName); + CPPUNIT_TEST(getFileName_001); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline OUString getFileURL() const + + class getFileURL : public CppUnit::TestFixture + { + DirectoryItem rItem; + + public: + void setUp() override + { + createTestFile(aTmpName6); + osl::FileBase::RC nError = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + } + + void tearDown() override + { + deleteTestFile(aTmpName6); + } + + + void getFileURL_001() + { + FileStatus rFileStatus(osl_FileStatus_Mask_FileURL); + osl::FileBase::RC nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError); + + OUString aFileURL = rFileStatus.getFileURL(); + + CPPUNIT_ASSERT_MESSAGE("test for getFileURL function: ", + compareFileName(aFileURL, aTmpName6)); + } + + CPPUNIT_TEST_SUITE(getFileURL); + CPPUNIT_TEST(getFileURL_001); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline OUString getLinkTargetURL() const + + class getLinkTargetURL : public CppUnit::TestFixture + { + private: + OUString aTypeURL; + DirectoryItem rItem; + + public: + void setUp() override + { + aTypeURL = aUserDirectoryURL.copy(0); + concatURL(aTypeURL, aTmpName2); + createTestFile(aTypeURL); + } + + void tearDown() override + { + deleteTestFile(aTypeURL); + } + + void getLinkTargetURL_001() + { +#if 0 +#if (defined UNX) // Link file is not defined in Windows + // create a link file; + OUString aUStr_LnkFileSys(aTempDirectorySys), aUStr_SrcFileSys(aTempDirectorySys); + aUStr_LnkFileSys += aSlashURL + getCurrentPID() + "/link.file"; + aUStr_SrcFileSys += aSlashURL + getCurrentPID() + "/tmpname"; + + OString strLinkFileName, strSrcFileName; + strLinkFileName = OUStringToOString(aUStr_LnkFileSys, RTL_TEXTENCODING_ASCII_US); + strSrcFileName = OUStringToOString(aUStr_SrcFileSys, RTL_TEXTENCODING_ASCII_US); + + sal_Int32 fd; + fd = symlink(strSrcFileName.getStr(), strLinkFileName.getStr()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("in creating link file", static_cast<sal_Int32>(0), fd); + + // get linkTarget URL + auto nError = DirectoryItem::get(aLnkURL1, rItem); + CPPUNIT_ASSERT_EQUAL_MESSAGE("in getting link file item", osl::FileBase::E_None, nError); + + FileStatus rFileStatus(osl_FileStatus_Mask_LinkTargetURL); + nError = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL_MESSAGE("in getting link file status", osl::FileBase::E_None, nError); + OUString aFileURL = rFileStatus.getLinkTargetURL(); + + // remove link file + fd = remove(strLinkFileName.getStr()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("in deleting link file", static_cast<sal_Int32>(0), fd); + + CPPUNIT_ASSERT_MESSAGE("test for getLinkTargetURL function: Solaris version, create a file, and a link file link to it, get its LinkTargetURL and compare", + compareFileName(aFileURL, aTypeURL)); +#endif +#endif + } + + CPPUNIT_TEST_SUITE(getLinkTargetURL); + CPPUNIT_TEST(getLinkTargetURL_001); + CPPUNIT_TEST_SUITE_END(); + }; + + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::ctors, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::isValid, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::getFileType, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::getAttributes, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::getAccessTime, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::getModifyTime, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::getFileSize, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::getFileName, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::getFileURL, "osl_FileStatus"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_FileStatus::getLinkTargetURL, "osl_FileStatus"); + + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_FileStatus"); +} + +namespace osl_File +{ + + // testing the method + // File(const OUString& ustrFileURL) + + class ctors : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + void ctors_001() + { + File testFile(aTmpName4); + + osl::FileBase::RC nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + osl::FileBase::RC nError2 = testFile.close(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: initialize a File and test its open and close", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: initialize a File and test its open and close", + osl::FileBase::E_None, nError2); + } + + void ctors_002() + { + File testFile(aTmpName5); + char buffer[30] = "Test for File constructor"; + sal_uInt64 nCount; + + osl::FileBase::RC nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + osl::FileBase::RC nError2 = testFile.write(buffer, 30, nCount); + testFile.close(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: test relative file URL, this test show that relative file URL is also acceptable", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: test relative file URL, this test show that relative file URL is also acceptable", + osl::FileBase::E_None, nError2); + } + + CPPUNIT_TEST_SUITE(ctors); + CPPUNIT_TEST(ctors_001); + CPPUNIT_TEST(ctors_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC open(sal_uInt32 uFlags) + + class open : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void open_001() + { + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + auto nError2 = testFile.close(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("close error", osl::FileBase::E_None, nError2); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: open a regular file", + osl::FileBase::E_None, nError1); + } + + void open_002() + { + File testFile(aTmpName3); + + auto nError1 = testFile.open(osl_File_OpenFlag_Read); + + CPPUNIT_ASSERT_MESSAGE("test for open function: open a directory", + (File::E_INVAL == nError1) || (File::E_ACCES == nError1)); + } + + void open_003() + { + File testFile(aCanURL1); + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: open a non-exist file", + File::E_NOENT, nError1); + } + + void open_005() + { + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Create); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: create an exist file", + File::E_EXIST, nError1); + } + + void open_006() + { + File testFile(aCanURL1); + char buffer_write[30] = "Test for File open"; + char buffer_read[30]; + sal_uInt64 nCount_write, nCount_read; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); + auto nError2 = testFile.write(buffer_write, 30, nCount_write); + osl::FileBase::RC nError4 = testFile.setPos(osl_Pos_Absolut, 0); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError4); + auto nError3 = testFile.read(buffer_read, 10, nCount_read); + + osl::FileBase::RC nError5 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError5); + osl::FileBase::RC nError6 = osl::File::remove(aCanURL1); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError6); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: test for osl_File_OpenFlag_Read, osl_File_OpenFlag_Write and osl_File_OpenFlag_Create", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: test for osl_File_OpenFlag_Read, osl_File_OpenFlag_Write and osl_File_OpenFlag_Create", + osl::FileBase::E_None, nError2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: test for osl_File_OpenFlag_Read, osl_File_OpenFlag_Write and osl_File_OpenFlag_Create", + osl::FileBase::E_None, nError3); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: test for osl_File_OpenFlag_Read, osl_File_OpenFlag_Write and osl_File_OpenFlag_Create", + sal_uInt64(30), nCount_write); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: test for osl_File_OpenFlag_Read, osl_File_OpenFlag_Write and osl_File_OpenFlag_Create", + sal_uInt64(10), nCount_read); + } + + CPPUNIT_TEST_SUITE(open); + CPPUNIT_TEST(open_001); + CPPUNIT_TEST(open_002); + CPPUNIT_TEST(open_003); + CPPUNIT_TEST(open_005); + CPPUNIT_TEST(open_006); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC close() + + class close : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void close_001() + { + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + auto nError2 = testFile.close(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for close function: close a regular file", + osl::FileBase::E_None, nError2); + } + + void close_002() + { + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + auto nError2 = testFile.close(); + + auto nError3 = testFile.setPos(osl_Pos_Absolut, 0); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for close function: manipulate a file after it has been closed", + osl::FileBase::E_None, nError2); + CPPUNIT_ASSERT_MESSAGE("test for close function: manipulate a file after it has been closed", + (osl::FileBase::E_None != nError3)); + } + + CPPUNIT_TEST_SUITE(close); + CPPUNIT_TEST(close_001); + CPPUNIT_TEST(close_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC setPos(sal_uInt32 uHow, sal_Int64 uPos) + + class setPos : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + // write chars into the file. + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_write = 0; + nError1 = testFile.write(pBuffer_Char, sizeof(pBuffer_Char), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + void setPos_001() + { + File testFile(aTmpName4); + char buffer_read[2]; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.setPos(osl_Pos_Absolut, 26); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_read = 0; + nError1 = testFile.read(buffer_read, 1, nCount_read); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for setPos function: test for osl_Pos_Absolut, set the position to 26, test if the 26th char in file is correct", + pBuffer_Char[26], buffer_read[0]); + } + + void setPos_002() + { + File testFile(aTmpName4); + char buffer_read[2]; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.setPos(osl_Pos_Absolut, sizeof(pBuffer_Char) - 2); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.setPos(osl_Pos_Current, 0); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_read = 0; + nError1 = testFile.read(buffer_read, 1, nCount_read); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for setPos function: test for osl_Pos_Current, set the position to end, test if the (end -1) char in file is correct", + pBuffer_Char[sizeof(pBuffer_Char) - 2], buffer_read[0]); + } + + void setPos_003() + { + File testFile(aTmpName4); + char buffer_read[2]; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // the file size is smaller than 100 + nError1 = testFile.setPos(osl_Pos_End, -100); + CPPUNIT_ASSERT_EQUAL_MESSAGE("should return error", osl::FileBase::E_INVAL, nError1); + + nError1 = testFile.setPos(osl_Pos_End, -53); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_read = 0; + nError1 = testFile.read(buffer_read, 1, nCount_read); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for setPos function: test for osl_Pos_End, set the position to end, test if the first char in file is correct", + pBuffer_Char[0], buffer_read[0]); + } + + CPPUNIT_TEST_SUITE(setPos); + CPPUNIT_TEST(setPos_001); + CPPUNIT_TEST(setPos_002); + CPPUNIT_TEST(setPos_003); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC getPos(sal_uInt64& uPos) + + class getPos : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + // write chars into the file. + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_write = 0; + nError1 = testFile.write(pBuffer_Char, sizeof(pBuffer_Char), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void getPos_001() + { + File testFile(aTmpName4); + sal_uInt64 nFilePointer; + + auto nError1 = testFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, nError1); + + nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.setPos(osl_Pos_Absolut, 26); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getPos function: set the position to 26, get position and check if it is right", + static_cast<sal_uInt64>(26), nFilePointer); + } + + CPPUNIT_TEST_SUITE(getPos); + CPPUNIT_TEST(getPos_001); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC isEndOfFile(sal_Bool *pIsEOF) + + class isEndOfFile : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + // write chars into the file. + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_write = 0; + nError1 = testFile.write(pBuffer_Char, sizeof(pBuffer_Char), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void isEndOfFile_001() + { + File testFile(aTmpName4); + sal_Bool bEOF = false; + sal_Bool *pEOF = &bEOF; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.setPos(osl_Pos_End, 0); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.isEndOfFile(pEOF); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_MESSAGE("test for isEndOfFile function: set the position to end, check if reach end", + *pEOF); + } + + void isEndOfFile_002() + { + File testFile(aTmpName4); + sal_Bool bEOF = false; + sal_Bool *pEOF = &bEOF; + sal_uInt64 nFilePointer = 0; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.setPos(osl_Pos_Absolut, 0); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + *pEOF = false; + + while (!(*pEOF)) + { + nError1 = testFile.isEndOfFile(pEOF); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.setPos(osl_Pos_Current, 1); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + nError1 = testFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for isEndOfFile function: use isEndOfFile to move pointer step by step", + static_cast<sal_uInt64>(sizeof(pBuffer_Char) + 1), nFilePointer); + } + CPPUNIT_TEST_SUITE(isEndOfFile); + CPPUNIT_TEST(isEndOfFile_001); + CPPUNIT_TEST(isEndOfFile_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC setSize(sal_uInt64 uSize) + + class setSize : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + // write chars into the file. + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_write = 0; + nError1 = testFile.write(pBuffer_Char, sizeof(pBuffer_Char), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void setSize_001() + { + File testFile(aTmpName4); + sal_uInt64 nFilePointer; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // enlarge the file to size of 100; + nError1 = testFile.setSize(100); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // get the file size; + nError1 = testFile.setPos(osl_Pos_End, 0); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for setSize function: enlarge the file ", + static_cast<sal_uInt64>(100), nFilePointer); + } + + void setSize_002() + { + File testFile(aTmpName4); + sal_uInt64 nFilePointer; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // enlarge the file to size of 100; + nError1 = testFile.setSize(10); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // get the file size; + nError1 = testFile.setPos(osl_Pos_End, 0); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for setSize function: truncate the file ", + static_cast<sal_uInt64>(10), nFilePointer); + } + + CPPUNIT_TEST_SUITE(setSize); + CPPUNIT_TEST(setSize_001); + CPPUNIT_TEST(setSize_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC read(void *pBuffer, sal_uInt64 uBytesRequested, sal_uInt64& rBytesRead) + + class read : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + // write chars into the file. + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_write = 0; + nError1 = testFile.write(pBuffer_Char, sizeof(pBuffer_Char), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void read_001() + { + File testFile(aTmpName4); + sal_uInt64 nFilePointer; + char buffer_read[10]; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_read = 0; + nError1 = testFile.read(buffer_read, 10, nCount_read); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for read function: read whole content in the file to a buffer", + sal_uInt64(10), nFilePointer); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for read function: read whole content in the file to a buffer", + 0, strncmp(buffer_read, pBuffer_Char, 10)); + } + + void read_002() + { + File testFile(aTmpName4); + sal_uInt64 nFilePointer; + char buffer_read[26]; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.setPos(osl_Pos_Absolut, 26); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_read = 0; + nError1 = testFile.read(buffer_read, 26, nCount_read); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for read function: read from a special position in the file", + sal_uInt64(52), nFilePointer); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for read function: read from a special position in the file", + sal_uInt64(26), nCount_read); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for read function: read from a special position in the file", + 0, strncmp(buffer_read, &pBuffer_Char[26], 26)); + } + + CPPUNIT_TEST_SUITE(read); + CPPUNIT_TEST(read_001); + CPPUNIT_TEST(read_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC write(const void *pBuffer, sal_uInt64 uBytesToWrite, sal_uInt64& rBytesWritten) + + class write : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpname. + createTestFile(aTmpName6); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpname. + deleteTestFile(aTmpName6); + } + + + void write_001() + { + File testFile(aTmpName6); + sal_uInt64 nFilePointer; + char buffer_read[10]; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + sal_uInt64 nCount_write = 0, nCount_read = 0; + // write chars into the file. + nError1 = testFile.write(pBuffer_Char, 10, nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // get the current pointer; + nError1 = testFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // reset pointer to the beginning; + nError1 = testFile.setPos(osl_Pos_Absolut, 0); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.read(buffer_read, 10, nCount_read); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for write function: read whole content in the file to a buffer. Note, buffer size can not smaller than the read size", + sal_uInt64(10), nFilePointer); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for write function: read whole content in the file to a buffer. Note, buffer size can not smaller than the read size", + 0, strncmp(buffer_read, pBuffer_Char, 10)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for write function: read whole content in the file to a buffer. Note, buffer size can not smaller than the read size", + sal_uInt64(10), nCount_write); + } + + CPPUNIT_TEST_SUITE(write); + CPPUNIT_TEST(write_001); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC readLine(::ByteSequence& aSeq) + + class readLine : public CppUnit::TestFixture + { + rtl::ByteSequence aSequence; + + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpname. + createTestFile(aTmpName6); + + // write some strings into the file. + File testFile(aTmpName6); + char ppStrSeq[3][27] = { "abcde\n", + "1234567890\n", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + }; + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + sal_uInt64 nCount_write = 0; + for (int nCount = 0; nCount < 3; nCount++) + { + nError1 = testFile.write(ppStrSeq[nCount], strlen(ppStrSeq[nCount]), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpname. + deleteTestFile(aTmpName6); + } + + + void readLine_001() + { + File testFile(aTmpName6); + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.readLine(aSequence); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for readLine function: read the first line of the file.", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for readLine function: read the first line of the file.", + 0, strncmp(reinterpret_cast<char *>(aSequence.getArray()), pBuffer_Char, 5)); + } + + void readLine_002() + { + File testFile(aTmpName6); + sal_Bool bEOF = false; + sal_Bool *pEOF = &bEOF; + + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + for (int nCount = 0; nCount < 3; nCount++) + { + nError1 = testFile.readLine(aSequence); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + nError1 = testFile.isEndOfFile(pEOF); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_MESSAGE("test for readLine function: read three lines of the file and check the file pointer moving.", + *pEOF); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for readLine function: read three lines of the file and check the file pointer moving.", + 0, strncmp(reinterpret_cast<char *>(aSequence.getArray()), &pBuffer_Char[26], 26)); + } + CPPUNIT_TEST_SUITE(readLine); + CPPUNIT_TEST(readLine_001); + CPPUNIT_TEST(readLine_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC copy(const OUString& ustrSourceFileURL, const OUString& ustrDestFileURL) + + class copy : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + // write chars into the file. + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_write = 0; + nError1 = testFile.write(pBuffer_Char, sizeof(pBuffer_Char), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + void copy_001() + { + File testFile(aTmpName6); + + // copy $TEMP/tmpdir/tmpname to $TEMP/tmpname. + auto nError1 = File::copy(aTmpName4, aTmpName6); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // check + nError1 = testFile.open(osl_File_OpenFlag_Create); + deleteTestFile(aTmpName6); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for copy function: copy file to upper directory", + osl::FileBase::E_EXIST, nError1); + } + + void copy_002() + { + // copy $TEMP/tmpdir/tmpname to $TEMP/tmpdir. + auto nError1 = File::copy(aTmpName4, aTmpName3); + + CPPUNIT_ASSERT_MESSAGE("test for copy function: use directory as destination", + (osl::FileBase::E_ISDIR == nError1) ||(osl::FileBase::E_ACCES == nError1)); + } + + void copy_003() + { +#if 0 + // copy $TEMP/tmpdir/tmpname to $ROOT/tmpname. + auto nError1 = File::copy(aTmpName4, aTmpName7); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for copy function: copy to an illegal place", + osl::FileBase::E_ACCES, nError1); +#endif + } + + void copy_004() + { + // copy $TEMP/tmpname to $TEMP/tmpdir/tmpname. + auto nError1 = File::copy(aTmpName6, aTmpName4); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for copy function: copy a not exist file", + osl::FileBase::E_NOENT, nError1); + } + + void copy_005() + { + // copy $TEMP/tmpname to $TEMP/system.path using system path. + auto nError1 = File::copy(aTmpName6, aSysPath1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for copy function: copy a file using system file path", + osl::FileBase::E_INVAL, nError1); + } + + void copy_006() + { + createTestFile(aTmpName6); + File tmpFile(aTmpName6); + tmpFile.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Read); + tmpFile.setSize(200); + tmpFile.close(); + // copy to new path + auto nError1 = File::copy(aTmpName6, aTmpName4); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // check if is the new file + File newFile(aTmpName4); + newFile.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Read); + nError1 = newFile.setPos(osl_Pos_End, 0); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + sal_uInt64 nFilePointer; + nError1 = newFile.getPos(nFilePointer); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + newFile.close(); + deleteTestFile(aTmpName6); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for copy function: the dest file exist", + static_cast<sal_uInt64>(200), nFilePointer); + } + + CPPUNIT_TEST_SUITE(copy); + CPPUNIT_TEST(copy_001); + CPPUNIT_TEST(copy_002); + CPPUNIT_TEST(copy_003); + CPPUNIT_TEST(copy_004); + CPPUNIT_TEST(copy_005); + CPPUNIT_TEST(copy_006); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC move(const OUString& ustrSourceFileURL, const OUString& ustrDestFileURL) + + class move : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + // write chars into the file. + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_write = 0; + nError1 = testFile.write(pBuffer_Char, sizeof(pBuffer_Char), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void move_001() + { + // rename $TEMP/tmpdir/tmpname to $TEMP/canonical.name. + auto nError1 = File::move(aTmpName4, aCanURL1); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // check + File testFile(aCanURL1); + auto nError2 = testFile.open(osl_File_OpenFlag_Create); + deleteTestFile(aCanURL1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for move function: rename file to another directory", + osl::FileBase::E_EXIST, nError2); + } + + void move_002() + { +#ifdef _WIN32 + // move $TEMP/tmpdir/tmpname to $TEMP/tmpdir. + auto nError1 = File::move(aTmpName4, aTmpName3); + // returned osl::FileBase::E_ACCES on WNT + CPPUNIT_ASSERT_MESSAGE("test for move function: use directory as destination", + (osl::FileBase::E_ACCES == nError1 || osl::FileBase::E_ISDIR == nError1) ||(osl::FileBase::E_EXIST == nError1)); +#endif + } + + void move_003() + { +#if 0 + // move $TEMP/tmpdir/tmpname to $ROOT/tmpname. + auto nError1 = File::move(aTmpName4, aTmpName7); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for move function: move to an illegal place", + osl::FileBase::E_ACCES, nError1); +#endif + } + + void move_004() + { + // move $TEMP/tmpname to $TEMP/tmpdir/tmpname. + auto nError1 = File::move(aTmpName6, aTmpName4); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for move function: move a not exist file", + osl::FileBase::E_NOENT, nError1); + } + + void move_005() + { + // move $TEMP/tmpname to $TEMP/system.path using system path. + auto nError1 = File::move(aTmpName6, aSysPath1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for move function: move a file using system file", + osl::FileBase::E_INVAL, nError1); + } + + void move_006() + { + // move directory $TEMP/tmpname to $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName6); + auto nError1 = File::move(aTmpName6, aTmpName4); + // move file $TEMP/tmpdir/tmpname to $TEMP/tmpname + auto nError2 = File::move(aTmpName4, aTmpName6); + deleteTestDirectory(aTmpName6); +#if defined(_WIN32) + deleteTestDirectory(aTmpName4);// in Windows, it can be moved!!!!! this is only for not influence the following test. + deleteTestFile(aTmpName6); + nError1 = osl::FileBase::E_NOTDIR; + nError2 = osl::FileBase::E_ISDIR; +#endif + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for move function: move a directory to an exist file with same name, did not pass in (W32)", + osl::FileBase::E_NOTDIR, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for move function: move a directory to an exist file with same name, did not pass in (W32)", + osl::FileBase::E_ISDIR, nError2); + } + + void move_007() + { + // create directory $TEMP/tmpname. + createTestDirectory(aTmpName6); + // move directory $TEMP/tmpdir to $TEMP/tmpname/tmpdir + auto nError1 = File::move(aTmpName3, aTmpName8); + // check + auto nError2 = Directory::create(aTmpName8); + File::move(aTmpName8, aTmpName3); + deleteTestDirectory(aTmpName6); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for move function: move a directory to an exist file with same name", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for move function: move a directory to an exist file with same name", + osl::FileBase::E_EXIST, nError2); + } + + // bugid# 115420, after the bug fix, add the case + CPPUNIT_TEST_SUITE(move); + CPPUNIT_TEST(move_001); + CPPUNIT_TEST(move_002); + CPPUNIT_TEST(move_003); + CPPUNIT_TEST(move_004); + CPPUNIT_TEST(move_005); + CPPUNIT_TEST(move_006); + CPPUNIT_TEST(move_007); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC remove(const OUString& ustrFileURL) + + class remove : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + + // write chars into the file. + File testFile(aTmpName4); + + auto nError1 = testFile.open(osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + sal_uInt64 nCount_write = 0; + nError1 = testFile.write(pBuffer_Char, sizeof(pBuffer_Char), nCount_write); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = testFile.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void remove_001() + { + // remove $TEMP/tmpdir/tmpname. + auto nError1 = File::remove(aTmpName4); + // check + File testFile(aTmpName4); + auto nError2 = testFile.open(osl_File_OpenFlag_Create); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for remove function: remove a file", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_MESSAGE("test for remove function: remove a file", + (osl::FileBase::E_EXIST != nError2)); + } + + void remove_002() + { + // remove $TEMP/tmpname. + auto nError1 = File::remove(aTmpName6); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for remove function: remove a file not exist", + osl::FileBase::E_NOENT, nError1); + } + + void remove_003() + { + // remove $TEMP/system/path. + auto nError1 = File::remove(aSysPath2); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for remove function: removing a file not using full qualified URL", + osl::FileBase::E_INVAL, nError1); + } + + void remove_004() + { + // remove $TEMP/tmpdir. + auto nError1 = File::remove(aTmpName3); + + CPPUNIT_ASSERT_MESSAGE("test for remove function: remove a directory", + (osl::FileBase::E_ISDIR == nError1) || (osl::FileBase::E_ACCES == nError1)); + } + + CPPUNIT_TEST_SUITE(remove); + CPPUNIT_TEST(remove_001); + CPPUNIT_TEST(remove_002); + CPPUNIT_TEST(remove_003); + CPPUNIT_TEST(remove_004); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC setAttributes(const OUString& ustrFileURL, sal_uInt64 uAttributes) + + class setAttributes : public CppUnit::TestFixture + { + private: + DirectoryItem rItem; + + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestFile(aTmpName6); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName6); + } + + + void setAttributes_001() + { + // on windows, only can set 2 attributes: osl_File_Attribute_ReadOnly, osl_File_Attribute_Hidden +#ifdef UNX + // set the file to readonly + auto nError2 = File::setAttributes(aTmpName6, osl_File_Attribute_ReadOnly | osl_File_Attribute_GrpRead | osl_File_Attribute_OwnRead | osl_File_Attribute_OthRead); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // get the file attributes + FileStatus rFileStatus(osl_FileStatus_Mask_Attributes); + nError1 = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + if (geteuid() == 0) // as root, access(W_OK) may be true despite mode + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for setAttributes function: set file attributes and get it to verify.", + static_cast<sal_uInt64>(osl_File_Attribute_GrpRead | osl_File_Attribute_OwnRead | osl_File_Attribute_OthRead), + rFileStatus.getAttributes()); + } + else + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for setAttributes function: set file attributes and get it to verify.", + static_cast<sal_uInt64>(osl_File_Attribute_ReadOnly | osl_File_Attribute_GrpRead | osl_File_Attribute_OwnRead | osl_File_Attribute_OthRead), + rFileStatus.getAttributes()); + } +#else + // please see GetFileAttributes + auto nError2 = File::setAttributes(aTmpName6, osl_File_Attribute_ReadOnly); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // get the file attributes + FileStatus rFileStatus(osl_FileStatus_Mask_Attributes); + nError1 = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // here the file has 2 Attributes: FILE_ATTRIBUTE_READONLY and FILE_ATTRIBUTE_NORMAL, + // but FILE_ATTRIBUTE_NORMAL is valid only if used alone, so this is maybe a bug + /*OString aString = OUStringToOString(aTmpName6, RTL_TEXTENCODING_ASCII_US); + DWORD dwFileAttributes = GetFileAttributes(aString.getStr()); + if (dwFileAttributes & FILE_ATTRIBUTE_NORMAL) + printf("has normal attribute"); + if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) + printf("has readonly attribute"); + */ + CPPUNIT_ASSERT_MESSAGE("test for setAttributes function: set file attributes READONLY and get it to verify.", + (osl_File_Attribute_ReadOnly & rFileStatus.getAttributes()) != 0); +#endif + } + void setAttributes_002() + { + // on UNX, can not set hidden attribute to file, rename file can set the attribute +#ifdef _WIN32 + // set the file to hidden + auto nError2 = File::setAttributes(aTmpName6, osl_File_Attribute_Hidden); + + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // get the file attributes + FileStatus rFileStatus(osl_FileStatus_Mask_Attributes); + nError1 = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_MESSAGE("test for setAttributes function: set file attributes and get it to verify.", + (osl_File_Attribute_Hidden & rFileStatus.getAttributes()) != 0); +#endif + } + + CPPUNIT_TEST_SUITE(setAttributes); + CPPUNIT_TEST(setAttributes_001); + CPPUNIT_TEST(setAttributes_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC setTime( + // const OUString& ustrFileURL, + // const TimeValue& rCreationTime, + // const TimeValue& rLastAccessTime, + // const TimeValue& rLastWriteTime) + + class setTime : public CppUnit::TestFixture + { + private: + DirectoryItem rItem; + + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestFile(aTmpName6); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName6); + } + + + void setTime_001() + { + TimeValue *pTV_current = nullptr; + CPPUNIT_ASSERT((pTV_current = static_cast<TimeValue*>(malloc(sizeof(TimeValue)))) != nullptr); + TimeValue *pTV_creation = nullptr; + CPPUNIT_ASSERT((pTV_creation = static_cast<TimeValue*>(malloc(sizeof(TimeValue)))) != nullptr); + TimeValue *pTV_access = nullptr; + CPPUNIT_ASSERT((pTV_access = static_cast<TimeValue*>(malloc(sizeof(TimeValue)))) != nullptr); + TimeValue *pTV_modify = nullptr; + CPPUNIT_ASSERT((pTV_modify = static_cast<TimeValue*>(malloc(sizeof(TimeValue)))) != nullptr); + + // get current time + bool bOk = osl_getSystemTime(pTV_current); + CPPUNIT_ASSERT(bOk); + + // set the file time + auto nError2 = File::setTime(aTmpName6, *pTV_current, *pTV_current, *pTV_current); + CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError2).getStr(), osl::FileBase::E_None, nError2); + + // get the file access time, creation time, modify time + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError1).getStr(), osl::FileBase::E_None, nError1); + + FileStatus rFileStatus(osl_FileStatus_Mask_AccessTime); + nError1 = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError1).getStr(), osl::FileBase::E_None, nError1); + *pTV_access = rFileStatus.getAccessTime(); + + FileStatus rFileStatus1(osl_FileStatus_Mask_CreationTime); + nError1 = rItem.getFileStatus(rFileStatus1); + CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError1).getStr(), osl::FileBase::E_None, nError1); + *pTV_creation = rFileStatus1.getCreationTime(); + + FileStatus rFileStatus2(osl_FileStatus_Mask_ModifyTime); + nError1 = rItem.getFileStatus(rFileStatus2); + CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError1).getStr(), osl::FileBase::E_None, nError1); + *pTV_modify = rFileStatus2.getModifyTime(); + + CPPUNIT_ASSERT_MESSAGE("test for setTime function: set access time then get it. time precision is still a problem for it cut off the nanosec.", + t_compareTime(pTV_access, pTV_current, delta)); +#if defined(_WIN32) + // Unfortunately there is no way to get the creation time of a file under Unix (it's a Windows only feature). + // That means the flag osl_FileStatus_Mask_CreationTime should be deprecated under Unix. + CPPUNIT_ASSERT_MESSAGE("test for setTime function: set creation time then get it. ", + t_compareTime(pTV_creation, pTV_current, delta)); +#endif + CPPUNIT_ASSERT_MESSAGE("test for setTime function: set modify time then get it. ", + t_compareTime(pTV_modify, pTV_current, delta)); + free(pTV_current); + free(pTV_creation); + free(pTV_access); + free(pTV_modify); + } + + CPPUNIT_TEST_SUITE(setTime); + CPPUNIT_TEST(setTime_001); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC sync() + + class sync : public CppUnit::TestFixture + { + private: + DirectoryItem rItem; + + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestFile(aTmpName6); + + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName6); + } + + // test case: if The file is located on a read only file system. + void sync_001() + { + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + File tmp_file(aTmpName6); + osl::FileBase::RC err = tmp_file.open(osl_File_OpenFlag_Write); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("File open failed", osl::FileBase::E_None, err); + + char buffer[50000]; + sal_uInt64 written = 0; + nError1 = tmp_file.write(static_cast<void*>(buffer), sizeof(buffer), written); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write failed!", osl::FileBase::E_None, nError1); + + // set the file to readonly + auto nError2 = File::setAttributes(aTmpName6, osl_File_Attribute_ReadOnly | osl_File_Attribute_GrpRead | osl_File_Attribute_OwnRead | osl_File_Attribute_OthRead); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + + nError2 = tmp_file.sync(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("can not sync to readonly file!", osl::FileBase::E_None, nError2); + + tmp_file.close(); + } + // test case:no enough space, how to create such case???see test_cpy_wrt_file.cxx::test_osl_writeFile + + CPPUNIT_TEST_SUITE(sync); + CPPUNIT_TEST(sync_001); + CPPUNIT_TEST_SUITE_END(); + }; + + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::ctors, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::open, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::close, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::setPos, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::getPos, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::isEndOfFile, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::setSize, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::read, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::write, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::readLine, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::copy, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::move, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::remove, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::setAttributes, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::setTime, "osl_File"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_File::sync, "osl_File"); + + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_File"); +} + +// Beginning of the test cases for DirectoryItem class + +namespace osl_DirectoryItem +{ + // testing the method + // DirectoryItem(): _pData(NULL) + + class ctors : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpname. + createTestFile(aTmpName6); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpname. + deleteTestFile(aTmpName6); + } + + void ctors_001() + { + File testFile(aTmpName6); + DirectoryItem rItem; // constructor + + // get the DirectoryItem. + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: initialize a new instance of DirectoryItem and get an item to check.", + osl::FileBase::E_None, nError1); + } + + CPPUNIT_TEST_SUITE(ctors); + CPPUNIT_TEST(ctors_001); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // DirectoryItem(const DirectoryItem& rItem): _pData(rItem._pData) + + class copy_assin_Ctors : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpname. + createTestFile(aTmpName6); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpname. + deleteTestFile(aTmpName6); + } + + + void copy_assin_Ctors_001() + { + DirectoryItem rItem; // constructor + // get the DirectoryItem. + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + DirectoryItem copyItem(rItem); // copy constructor + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + nError1 = copyItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_MESSAGE("test for copy_assin_Ctors function: use copy constructor to get an item and check filename.", + compareFileName(rFileStatus.getFileName(), aTmpName2)); + } + + void copy_assin_Ctors_002() + { + DirectoryItem rItem; // constructor + // get the DirectoryItem. + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + DirectoryItem copyItem; + copyItem = rItem; // assignment operator + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + nError1 = copyItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_MESSAGE("test for copy_assin_Ctors function: test assignment operator here since it is same as copy constructor in test way.", + compareFileName(rFileStatus.getFileName(), aTmpName2)); + } + + CPPUNIT_TEST_SUITE(copy_assin_Ctors); + CPPUNIT_TEST(copy_assin_Ctors_001); + CPPUNIT_TEST(copy_assin_Ctors_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline sal_Bool is() + + class is : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpname. + createTestFile(aTmpName6); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpname. + deleteTestFile(aTmpName6); + } + + void is_001() + { + DirectoryItem rItem; // constructor + + CPPUNIT_ASSERT_MESSAGE("test for is function: use an uninitialized instance.", + !rItem.is()); + } + + void is_002() + { + DirectoryItem rItem; // constructor + // get the DirectoryItem. + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_MESSAGE("test for is function: use an uninitialized instance.", + rItem.is()); + } + + CPPUNIT_TEST_SUITE(is); + CPPUNIT_TEST(is_001); + CPPUNIT_TEST(is_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // static inline RC get(const OUString& ustrFileURL, DirectoryItem& rItem) + + class get : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpname. + createTestFile(aTmpName6); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpname. + deleteTestFile(aTmpName6); + } + + + void get_001() + { + DirectoryItem rItem; + auto nError2 = DirectoryItem::get(aTmpName6, rItem); + + // check the file name + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + auto nError1 = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for get function: use copy constructor to get an item and check filename.", + osl::FileBase::E_None, nError2); + CPPUNIT_ASSERT_MESSAGE("test for get function: use copy constructor to get an item and check filename.", + compareFileName(rFileStatus.getFileName(), aTmpName2)); + } + + void get_002() + { + DirectoryItem rItem; + auto nError1 = DirectoryItem::get(aSysPath1, rItem); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for get function: use a system name instead of a URL.", + osl::FileBase::E_INVAL, nError1); + } + + void get_003() + { + DirectoryItem rItem; + + auto nError1 = DirectoryItem::get(aTmpName3, rItem); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for get function: use a non existed file URL.", + osl::FileBase::E_NOENT, nError1); + } + + CPPUNIT_TEST_SUITE(get); + CPPUNIT_TEST(get_001); + CPPUNIT_TEST(get_002); + CPPUNIT_TEST(get_003); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC getFileStatus(FileStatus& rStatus) + + class getFileStatus : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void getFileStatus_001() + { + DirectoryItem rItem; + // get the DirectoryItem. + auto nError1 = DirectoryItem::get(aTmpName4, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // check the file name + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + auto nError2 = rItem.getFileStatus(rFileStatus); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getFileStatus function: get file status and check filename", + osl::FileBase::E_None, nError2); + CPPUNIT_ASSERT_MESSAGE("test for getFileStatus function: get file status and check filename", + compareFileName(rFileStatus.getFileName(), aTmpName2)); + } + + void getFileStatus_002() + { + DirectoryItem rItem; // constructor + // get the DirectoryItem. + auto nError1 = DirectoryItem::get(aTmpName6, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_NOENT, nError1); + + // check the file name + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + auto nError2 = rItem.getFileStatus(rFileStatus); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getFileStatus function: file not existed", + osl::FileBase::E_INVAL, nError2); + } + + void getFileStatus_003() + { + DirectoryItem rItem; // constructor + // get the DirectoryItem. + auto nError1 = DirectoryItem::get(aTmpName3, rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // check the file name + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + auto nError2 = rItem.getFileStatus(rFileStatus); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getFileStatus function: get directory information", + osl::FileBase::E_None, nError2); + CPPUNIT_ASSERT_MESSAGE("test for getFileStatus function: get directory information", + compareFileName(rFileStatus.getFileName(), aTmpName1)); + } + + CPPUNIT_TEST_SUITE(getFileStatus); + CPPUNIT_TEST(getFileStatus_001); + CPPUNIT_TEST(getFileStatus_002); + CPPUNIT_TEST(getFileStatus_003); + CPPUNIT_TEST_SUITE_END(); + }; + + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_DirectoryItem::ctors, "osl_DirectoryItem"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_DirectoryItem::copy_assin_Ctors, "osl_DirectoryItem"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_DirectoryItem::is, "osl_DirectoryItem"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_DirectoryItem::get, "osl_DirectoryItem"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_DirectoryItem::getFileStatus, "osl_DirectoryItem"); + + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_DirectoryItem"); +} + +// Beginning of the test cases for Directory class + +namespace osl_Directory +{ + // testing the method + // Directory(const OUString& strPath): _pData(0), _aPath(strPath) + + class ctors : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + // LLA: t_print("tearDown done.\n"); + } + + + void ctors_001() + { + Directory testDirectory(aTmpName3); // constructor + + // open a directory + auto nError1 = testDirectory.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // close a directory + auto nError2 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: create an instance and check open and close", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: create an instance and check open and close", + osl::FileBase::E_None, nError2); + } + + void ctors_002() + { + Directory testDirectory(aTmpName9); // constructor + + // open a directory + auto nError1 = testDirectory.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // close a directory + auto nError2 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: relative URL, :-), it is also worked", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for ctors function: relative URL, :-), it is also worked", + osl::FileBase::E_None, nError2); + } + + CPPUNIT_TEST_SUITE(ctors); + CPPUNIT_TEST(ctors_001); + CPPUNIT_TEST(ctors_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC open() + + class open : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + void open_001() + { + Directory testDirectory(aTmpName3); + + // open a directory + auto nError1 = testDirectory.open(); + // check if directory is opened. + bool bOk = testDirectory.isOpen(); + // close a directory + auto nError2 = testDirectory.close(); + + CPPUNIT_ASSERT_MESSAGE("test for open function: open a directory and check for open", + bOk); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: open a directory and check for open", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: open a directory and check for open", + osl::FileBase::E_None, nError2); + } + + void open_002() + { + Directory testDirectory(aTmpName6); + + auto nError1 = testDirectory.open(); + if (nError1 == osl::FileBase::E_None) + { + auto nError2 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + } + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: open a file that is not existed", + osl::FileBase::E_NOENT, nError1); + } + + void open_003() + { + Directory testDirectory(aUserDirectorySys); + + auto nError1 = testDirectory.open(); + if (nError1 == osl::FileBase::E_None) + { + auto nError2 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + } + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for open function: using system path", + osl::FileBase::E_INVAL, nError1); + } + + void open_004() + { + Directory testDirectory(aTmpName4); + + auto nError1 = testDirectory.open(); + if (nError1 == osl::FileBase::E_None) + { + auto nError2 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + } + + CPPUNIT_ASSERT_MESSAGE("test for open function: open a file instead of a directory", + (osl::FileBase::E_NOTDIR == nError1) || (osl::FileBase::E_ACCES == nError1)); + } + + CPPUNIT_TEST_SUITE(open); + CPPUNIT_TEST(open_001); + CPPUNIT_TEST(open_002); + CPPUNIT_TEST(open_003); + CPPUNIT_TEST(open_004); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline sal_Bool isOpen() { return _pData != NULL; }; + + class isOpen : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempfile in $TEMP/tmpdir/tmpname. + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + } + + void tearDown() override + { + // remove the tempfile in $TEMP/tmpdir/tmpname. + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + } + + + void isOpen_001() + { + Directory testDirectory(aTmpName3); // constructor + + // open a directory + auto nError1 = testDirectory.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // check if directory is opened. + bool bOk = testDirectory.isOpen(); + // close a directory + auto nError2 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + CPPUNIT_ASSERT_MESSAGE("test for isOpen function: open a directory and check for open", + bOk); + } + + void isOpen_002() + { + Directory testDirectory(aTmpName3); // constructor + + // check if directory is opened. + bool bOk = testDirectory.isOpen(); + + CPPUNIT_ASSERT_MESSAGE("test for isOpen function: do not open a directory and check for open", + !bOk); + } + + CPPUNIT_TEST_SUITE(isOpen); + CPPUNIT_TEST(isOpen_001); + CPPUNIT_TEST(isOpen_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC close() + + class close : public CppUnit::TestFixture + { + public: + void setUp() override + { + // create a tempdirectory : $TEMP/tmpdir. + createTestDirectory(aTmpName3); + } + + void tearDown() override + { + // remove a tempdirectory : $TEMP/tmpdir. + deleteTestDirectory(aTmpName3); + } + + void close_001() + { + Directory testDirectory(aTmpName3); + + // open a directory + auto nError1 = testDirectory.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // close a directory + auto nError2 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + // check if directory is opened. + bool bOk = testDirectory.isOpen(); + + CPPUNIT_ASSERT_MESSAGE("test for isOpen function: close a directory and check for open", + !bOk); + } + + void close_002() + { + Directory testDirectory(aTmpName3); + + // close a directory + auto nError1 = testDirectory.close(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for isOpen function: close a not opened directory", + osl::FileBase::E_BADF, nError1); + } + + CPPUNIT_TEST_SUITE(close); + CPPUNIT_TEST(close_001); + CPPUNIT_TEST(close_002); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC reset() + + class reset : public CppUnit::TestFixture + { + private: + DirectoryItem rItem; + + public: + void setUp() override + { + // create a tempdirectory : $TEMP/tmpdir. + createTestDirectory(aTmpName3); + // create three files : $TEMP/tmpdir/tmpname, $TEMP/tmpdir/tmpdir, $TEMP/tmpdir/hiddenfile, + createTestFile(aTmpName3, aTmpName2); + createTestFile(aTmpName3, aTmpName1); + createTestFile(aTmpName3, aHidURL1); + } + + void tearDown() override + { + // remove three files : $TEMP/tmpdir/tmpname, $TEMP/tmpdir/tmpdir, $TEMP/tmpdir/hiddenfile, + deleteTestFile(aTmpName3, aHidURL1); + deleteTestFile(aTmpName3, aTmpName1); + deleteTestFile(aTmpName3, aTmpName2); + // remove a tempdirectory : $TEMP/tmpdir. + deleteTestDirectory(aTmpName3); + } + + + void reset_001() + { + Directory testDirectory(aTmpName3); // constructor + + // open a directory + auto nError1 = testDirectory.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // get first Item + nError1 = testDirectory.getNextItem(rItem, 1); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // check the file name of first Item + FileStatus rFileStatusFirst(osl_FileStatus_Mask_FileName); + nError1 = rItem.getFileStatus(rFileStatusFirst); + + // get second Item + // mindy: nError1 = testDirectory.getNextItem(rItem, 0); + // mindy: CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // reset enumeration + auto nError2 = testDirectory.reset(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError2); + // get reset Item, if reset does not work, getNextItem() should return the second Item (aTmpName1) + nError1 = testDirectory.getNextItem(rItem); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // check the file name again + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + nError1 = rItem.getFileStatus(rFileStatus); + // close a directory + nError1 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + bool bOK1,bOK2,bOK3; + bOK1 = compareFileName(rFileStatus.getFileName(), aTmpName2); + bOK2 = compareFileName(rFileStatus.getFileName(), aHidURL1); + bOK3 = compareFileName(rFileStatus.getFileName(), rFileStatusFirst.getFileName()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for reset function: get two directory item, reset it, then get again, check the filename", + osl::FileBase::E_None, nError2); + CPPUNIT_ASSERT_MESSAGE("test for reset function: get two directory item, reset it, then get again, check the filename", + (bOK1 || bOK2 || bOK3)); + } + + void reset_002() + { + Directory testDirectory(aTmpName6); // constructor + + // close a directory + auto nError1 = testDirectory.reset(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for reset function: reset a non existed directory", + osl::FileBase::E_NOENT, nError1); + } + + void reset_003() + { + Directory testDirectory(aTmpName4); // constructor + + // close a directory + auto nError1 = testDirectory.reset(); + + CPPUNIT_ASSERT_MESSAGE("test for reset function: reset a file instead of a directory", + (osl::FileBase::E_NOTDIR == nError1) || (osl::FileBase::E_NOENT == nError1)); + } + + void reset_004() + { + Directory testDirectory(aUserDirectorySys); // constructor + + // close a directory + auto nError1 = testDirectory.reset(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for reset function: use a system path", + osl::FileBase::E_INVAL, nError1); + } + + CPPUNIT_TEST_SUITE(reset); + CPPUNIT_TEST(reset_001); + CPPUNIT_TEST(reset_002); + CPPUNIT_TEST(reset_003); + CPPUNIT_TEST(reset_004); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline RC getNextItem(DirectoryItem& rItem, sal_uInt32 nHint = 0) + + class getNextItem : public CppUnit::TestFixture + { + private: + DirectoryItem rItem; + + public: + void setUp() override + { + // create a tempdirectory : $TEMP/tmpdir. + createTestDirectory(aTmpName3); + // create three files : $TEMP/tmpdir/tmpname, $TEMP/tmpdir/tmpdir, $TEMP/tmpdir/hiddenfile, + createTestFile(aTmpName3, aTmpName2); + createTestFile(aTmpName3, aTmpName1); + createTestFile(aTmpName3, aHidURL1); + + } + + void tearDown() override + { + // remove three files : $TEMP/tmpdir/tmpname, $TEMP/tmpdir/tmpdir, $TEMP/tmpdir/hiddenfile, + deleteTestFile(aTmpName3, aHidURL1); + deleteTestFile(aTmpName3, aTmpName1); + deleteTestFile(aTmpName3, aTmpName2); + // remove a tempdirectory : $TEMP/tmpdir. + deleteTestDirectory(aTmpName3); + } + + + void getNextItem_001() + { + Directory testDirectory(aTmpName3); // constructor + + // open a directory + auto nError1 = testDirectory.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // check the file name + bool bOk1 = false; + bool bOk2 = false; + bool bOk3 = false; + FileStatus rFileStatus(osl_FileStatus_Mask_FileName); + + for (int nCount = 0; nCount < 3; nCount++) + { + // get three Items + nError1 = testDirectory.getNextItem(rItem, 2); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + nError1 = rItem.getFileStatus(rFileStatus); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + // a special order is not guaranteed. So any file may occur on any time. + // But every file name should occur only once. + if (!bOk1 && compareFileName(rFileStatus.getFileName(), aTmpName1)) + { + bOk1 = true; + } + + if (!bOk2 && compareFileName(rFileStatus.getFileName(), aTmpName2)) + { + bOk2 = true; + } + + if (!bOk3 && compareFileName(rFileStatus.getFileName(), aHidURL1)) + { + bOk3 = true; + } + } + + // close a directory + nError1 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_MESSAGE("test for getNextItem function: retrieve three items and check their names.", + bOk1); + CPPUNIT_ASSERT_MESSAGE("test for getNextItem function: retrieve three items and check their names.", + bOk2); + CPPUNIT_ASSERT_MESSAGE("test for getNextItem function: retrieve three items and check their names.", + bOk3); + } + + void getNextItem_002() + { + Directory testDirectory(aTmpName3); // constructor + auto nError1 = testDirectory.getNextItem(rItem); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getNextItem function: retrieve an item in a directory which is not opened, also test for nHint's default value.", + osl::FileBase::E_INVAL, nError1); + } + + void getNextItem_003() + { + Directory testDirectory(aTmpName3); // constructor + + // open a directory + auto nError1 = testDirectory.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + osl::FileBase::RC nError2 = osl::FileBase::E_None; + for (int nCount = 0; nCount < 4; nCount++) + { + nError2 = testDirectory.getNextItem(rItem, 3); + } + + // close a directory + nError1 = testDirectory.close(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getNextItem function: retrieve 4 times in a directory which contain only 3 files.", + osl::FileBase::E_NOENT, nError2); + } + + void getNextItem_004() + { + // create a link file(can not on Windows), then check if getNextItem can get it. +#ifdef UNX + bool bLnkOK = false; + bool bFoundOK = false; + + OUString aUStr_LnkFileSys(aTempDirectorySys), aUStr_SrcFileSys(aTempDirectorySys); + aUStr_LnkFileSys += aSlashURL + "/tmpdir/link.file"; + aUStr_SrcFileSys += aSlashURL + "/tmpdir/tmpname"; + + OString strLinkFileName, strSrcFileName; + strLinkFileName = OUStringToOString(aUStr_LnkFileSys, RTL_TEXTENCODING_ASCII_US); + strSrcFileName = OUStringToOString(aUStr_SrcFileSys, RTL_TEXTENCODING_ASCII_US); + + // create a link file and link it to file "/tmp/PID/tmpdir/tmpname" + sal_Int32 fd = symlink(strSrcFileName.getStr(), strLinkFileName.getStr()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), fd); + Directory testDirectory(aTmpName3); + + // open a directory + auto nError1 = testDirectory.open(); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + OUString aFileName ("link.file"); + + while (true) { + nError1 = testDirectory.getNextItem(rItem, 4); + if (nError1 == osl::FileBase::E_None) { + FileStatus rFileStatus(osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Type); + rItem.getFileStatus(rFileStatus); + if (compareFileName(rFileStatus.getFileName(), aFileName)) + { + bFoundOK = true; + if (rFileStatus.getFileType() == FileStatus::Link) + { + bLnkOK = true; + break; + } + } + } + else + break; + } + fd = std::remove(strLinkFileName.getStr()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("remove link file failed", static_cast<sal_Int32>(0), fd); + CPPUNIT_ASSERT_MESSAGE("test for getNextItem function: check if can retrieve the link file name", + bFoundOK); + CPPUNIT_ASSERT_MESSAGE("test for getNextItem function: check if link file has file type link", + bLnkOK); +#endif + } + + CPPUNIT_TEST_SUITE(getNextItem); + CPPUNIT_TEST(getNextItem_001); + CPPUNIT_TEST(getNextItem_002); + CPPUNIT_TEST(getNextItem_003); + CPPUNIT_TEST(getNextItem_004); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC getVolumeInfo(const OUString& ustrDirectoryURL, VolumeInfo& rInfo) + + class getVolumeInfo : public CppUnit::TestFixture + { + public: + void checkValidMask(osl::VolumeInfo const& _aVolumeInfo, sal_Int32 _nMask) + { + if (_nMask == osl_VolumeInfo_Mask_FileSystemName) + { + // get file system name + OUString aFileSysName = _aVolumeInfo.getFileSystemName(); + + bool bRes2 = compareFileName(aFileSysName, aNullURL); + CPPUNIT_ASSERT_MESSAGE("test for getVolumeInfo function: getVolumeInfo of root directory.", + !bRes2); + } + + if (_nMask == osl_VolumeInfo_Mask_Attributes) + { + bool b1 = _aVolumeInfo.getRemoteFlag(); + bool b2 = _aVolumeInfo.getRemoveableFlag(); + bool b3 = _aVolumeInfo.getCompactDiscFlag(); + bool b4 = _aVolumeInfo.getFloppyDiskFlag(); + bool b5 = _aVolumeInfo.getFixedDiskFlag(); + bool b6 = _aVolumeInfo.getRAMDiskFlag(); + + OString sAttr; + if (b1) sAttr = "Remote"_ostr; + if (b2) sAttr += " Removeable"; + if (b3) sAttr += " CDROM"; + if (b4) sAttr += " Floppy"; + if (b5) sAttr += " FixedDisk"; + if (b6) sAttr += " RAMDisk"; + + printf("Attributes: %s\n", sAttr.getStr()); + } + if (_nMask == osl_VolumeInfo_Mask_TotalSpace) + { + // within Linux, df / * 1024 bytes is the result + sal_uInt64 nSize = _aVolumeInfo.getTotalSpace(); + printf("Total space: %" SAL_PRIuUINT64 "\n", nSize); + } + if (_nMask == osl_VolumeInfo_Mask_UsedSpace) + { + sal_uInt64 nSize = _aVolumeInfo.getUsedSpace(); + printf(" Used space: %" SAL_PRIuUINT64 "\n", nSize); + } + if (_nMask == osl_VolumeInfo_Mask_FreeSpace) + { + sal_uInt64 nSize = _aVolumeInfo.getFreeSpace(); + printf(" Free space: %" SAL_PRIuUINT64 "\n", nSize); + } + if (_nMask == osl_VolumeInfo_Mask_MaxNameLength) + { + sal_uInt32 nLength = _aVolumeInfo.getMaxNameLength(); + printf("max name length: %" SAL_PRIuUINT32 "\n", nLength); + } + if (_nMask == osl_VolumeInfo_Mask_MaxPathLength) + { + sal_uInt32 nLength = _aVolumeInfo.getMaxPathLength(); + printf("max path length: %" SAL_PRIuUINT32 "\n", nLength); + } + if (_nMask == osl_VolumeInfo_Mask_FileSystemCaseHandling) + { + bool bIsCase = _aVolumeInfo.isCaseSensitiveFileSystem(); + printf("filesystem case sensitive: %s\n", bIsCase ? "yes" : "no"); + } + } + + void checkVolumeInfo(sal_Int32 _nMask) + { + VolumeInfo aVolumeInfo(_nMask); + // call getVolumeInfo here + auto nError1 = Directory::getVolumeInfo(aVolURL1, aVolumeInfo); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "test for getVolumeInfo function: getVolumeInfo of root directory.", + osl::FileBase::E_None, nError1); + // LLA: IMHO it's not a bug, if VolumeInfo is not valid, it's a feature + // LLA: CPPUNIT_ASSERT_MESSAGE("mask is not valid", sal_True == aVolumeInfo.isValid(_nMask)); + if (aVolumeInfo.isValid(_nMask)) + checkValidMask(aVolumeInfo, _nMask); + } + + void getVolumeInfo_001_1() + { + sal_Int32 mask = osl_VolumeInfo_Mask_FileSystemName; + checkVolumeInfo(mask); + } + + void getVolumeInfo_001_2() + { + sal_Int32 mask = osl_VolumeInfo_Mask_Attributes; + checkVolumeInfo(mask); + } + + void getVolumeInfo_001_3() + { + sal_Int32 mask = osl_VolumeInfo_Mask_TotalSpace; + checkVolumeInfo(mask); + } + + void getVolumeInfo_001_4() + { + sal_Int32 mask = osl_VolumeInfo_Mask_UsedSpace; + checkVolumeInfo(mask); + } + + void getVolumeInfo_001_5() + { + sal_Int32 mask = osl_VolumeInfo_Mask_FreeSpace; + checkVolumeInfo(mask); + } + + void getVolumeInfo_001_6() + { + sal_Int32 mask = osl_VolumeInfo_Mask_MaxNameLength; + checkVolumeInfo(mask); + } + + void getVolumeInfo_001_7() + { + sal_Int32 mask = osl_VolumeInfo_Mask_MaxPathLength; + checkVolumeInfo(mask); + } + + void getVolumeInfo_001_8() + { + sal_Int32 mask = osl_VolumeInfo_Mask_FileSystemCaseHandling; + checkVolumeInfo(mask); + } + + void getVolumeInfo_002() + { + sal_Int32 mask = osl_VolumeInfo_Mask_FileSystemName; + VolumeInfo aVolumeInfo(mask); + // call getVolumeInfo here + + OUString aRootSysURL; + auto nError1 = osl::File::getFileURLFromSystemPath(aRootSys, aRootSysURL); + CPPUNIT_ASSERT_EQUAL_MESSAGE("can't convert root path to file url", osl::FileBase::E_None, nError1); + + nError1 = Directory::getVolumeInfo(aRootSys, aVolumeInfo); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getVolumeInfo function: use system path as parameter.", + osl::FileBase::E_INVAL, nError1); + } + + void getVolumeInfo_003() + { +// LLA: in Windows, it reply no error, it did not pass in (W32). +#if defined(UNX) && !defined(IOS) + sal_Int32 mask = osl_VolumeInfo_Mask_FileSystemName; + VolumeInfo aVolumeInfo(mask); + // call getVolumeInfo here + auto nError1 = Directory::getVolumeInfo(aTmpName3, aVolumeInfo); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for getVolumeInfo function: non-existence test. ", + osl::FileBase::E_NOENT, nError1); +#endif + } + + CPPUNIT_TEST_SUITE(getVolumeInfo); + CPPUNIT_TEST(getVolumeInfo_001_1); + CPPUNIT_TEST(getVolumeInfo_001_2); + CPPUNIT_TEST(getVolumeInfo_001_3); + CPPUNIT_TEST(getVolumeInfo_001_4); + CPPUNIT_TEST(getVolumeInfo_001_5); + CPPUNIT_TEST(getVolumeInfo_001_6); + CPPUNIT_TEST(getVolumeInfo_001_7); + CPPUNIT_TEST(getVolumeInfo_001_8); + CPPUNIT_TEST(getVolumeInfo_002); + CPPUNIT_TEST(getVolumeInfo_003); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC create(const OUString& ustrDirectoryURL) + + class create : public CppUnit::TestFixture + { + public: + void create_001() + { + // create directory in $TEMP/tmpdir + auto nError1 = Directory::create(aTmpName3); + // check for existence + auto nError2 = Directory::create(aTmpName3); + // remove it + deleteTestDirectory(aTmpName3); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for create function: create a directory and check its existence.", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for create function: create a directory and check its existence.", + osl::FileBase::E_EXIST, nError2); + } + + void create_002() + { +#if !defined(_WIN32) && !defined(MACOSX) && defined(SAL_UNX) + if (geteuid() == 0) // don't test if building as root + return; + + OUString aTmpDir; + auto nError1 = osl::FileBase::createTempFile(nullptr, nullptr, &aTmpDir); + CPPUNIT_ASSERT_EQUAL_MESSAGE("temp File creation failed", osl::FileBase::E_None, nError1); + + nError1 = File::remove(aTmpDir); + CPPUNIT_ASSERT_EQUAL_MESSAGE("temp File removal failed", osl::FileBase::E_None, nError1); + + nError1 = Directory::create(aTmpDir); + OString sError = "test for create function: create a directory '" + + OUStringToOString(aTmpDir, RTL_TEXTENCODING_ASCII_US) + + "' and check its existence."; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sError.getStr(), osl::FileBase::E_None, nError1); + osl_setFileAttributes(aTmpDir.pData, 0); // no access allowed now + + // Shouldn't be possible now to create a dir underneath it + OUString aTmpSubLevel = aTmpDir + "/notallowedhere"; + nError1 = Directory::create(aTmpSubLevel); + + // allow removal + osl_setFileAttributes(aTmpDir.pData, + osl_File_Attribute_OwnRead | + osl_File_Attribute_OwnWrite | + osl_File_Attribute_OwnExe); + deleteTestDirectory(aTmpDir); + sError = "test for create function: create a directory under '" + + OUStringToOString(aTmpDir, RTL_TEXTENCODING_ASCII_US) + + "' for access test."; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sError.getStr(), osl::FileBase::E_ACCES, nError1); +#endif + } + + void create_003() + { + // create directory in /tmpname + auto nError1 = Directory::create(aSysPath1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for create function: create a directory using system path.", + osl::FileBase::E_INVAL, nError1); + } + + CPPUNIT_TEST_SUITE(create); + CPPUNIT_TEST(create_001); + CPPUNIT_TEST(create_002); + CPPUNIT_TEST(create_003); + CPPUNIT_TEST_SUITE_END(); + }; + + // testing the method + // inline static RC remove(const OUString& ustrDirectoryURL) + + class remove : public CppUnit::TestFixture + { + public: + void remove_001() + { + // create directory in $TEMP/tmpdir + auto nError1 = Directory::create(aTmpName3); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // remove it + nError1 = Directory::remove(aTmpName3); + // check for existence + Directory rDirectory(aTmpName3); + auto nError2 = rDirectory.open(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for remove function: remove a directory and check its existence.", + osl::FileBase::E_None, nError1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for remove function: remove a directory and check its existence.", + osl::FileBase::E_NOENT, nError2); + } + + void remove_002() + { + // create directory in $TEMP/tmpdir + auto nError1 = Directory::create(aTmpName3); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + // try to remove it by system path + nError1 = Directory::remove(aSysPath3); + // check for existence + Directory rDirectory(aTmpName3); + auto nError2 = rDirectory.open(); + + if (nError2 != osl::FileBase::E_NOENT) + Directory::remove(aTmpName3); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for remove function: remove a directory by its system path, and check its existence.", + osl::FileBase::E_INVAL, nError1); + } + + void remove_003() + { + // try to remove a non-existed directory + auto nError1 = Directory::remove(aTmpName6); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("test for remove function: try to remove a non-existed directory.", + osl::FileBase::E_NOENT, nError1); + } + + void remove_004() + { + createTestFile(aTmpName6); + bool bExist = ifFileExist(aTmpName6); + // try to remove file. + auto nError1 = Directory::remove(aTmpName6); + deleteTestFile(aTmpName6); + + CPPUNIT_ASSERT_MESSAGE("test for remove function: try to remove a file but not directory.", + bExist); + CPPUNIT_ASSERT_MESSAGE("test for remove function: try to remove a file but not directory.", + (osl::FileBase::E_NOTDIR == nError1) || (osl::FileBase::E_NOENT == nError1)); + } + + void remove_005() + { + createTestDirectory(aTmpName3); + createTestFile(aTmpName4); + auto nError1 = Directory::remove(aTmpName3); + deleteTestFile(aTmpName4); + deleteTestDirectory(aTmpName3); + OString sError = "test for remove function: try to remove a directory that is not empty." + + errorToStr(nError1); +#if defined(__sun) + // on UNX, the implementation uses rmdir(), which EEXIST is thrown on Solaris when the directory is not empty, refer to: 'man -s 2 rmdir', while on linux, ENOTEMPTY is thrown. + // EEXIST The directory contains entries other than those for "." and "..". + printf("#Solaris test\n"); + CPPUNIT_ASSERT_MESSAGE(sError.getStr(), (osl::FileBase::E_EXIST == nError1)); +#else + CPPUNIT_ASSERT_EQUAL_MESSAGE(sError.getStr(), osl::FileBase::E_NOTEMPTY, nError1); +#endif + } + + CPPUNIT_TEST_SUITE(remove); + CPPUNIT_TEST(remove_001); + CPPUNIT_TEST(remove_002); + CPPUNIT_TEST(remove_003); + CPPUNIT_TEST(remove_004); + CPPUNIT_TEST(remove_005); + CPPUNIT_TEST_SUITE_END(); + }; + + // TEST Directory::createPath + + #ifdef _WIN32 + # define PATH_BUFFER_SIZE MAX_PATH + #else + # define PATH_BUFFER_SIZE PATH_MAX + #endif + +#define TEST_PATH_POSTFIX "hello/world" + + static OUString const & get_test_path() + { + static OUString test_path = []() + { + OUString tmp; + osl::FileBase::RC rc = osl::FileBase::getTempDirURL(tmp); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "Getting the location of TMP dir failed", + osl::FileBase::E_None, rc + ); + + OUString system_path; + rc = osl::FileBase::getSystemPathFromFileURL(tmp, system_path); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "Cannot convert the TMP dir to system path", + osl::FileBase::E_None, rc + ); + + OString tmp_x(OUStringToOString(system_path, RTL_TEXTENCODING_UTF8)); + if (tmp_x.lastIndexOf('/') != (tmp_x.getLength() - 1)) + tmp_x += "/"; + +#if !defined(_WIN32) && !defined(ANDROID) + // FIXME would be nice to create unique dir even on Windows + tmp_x += "XXXXXX"; + char *out = mkdtemp(const_cast<char*>(tmp_x.getStr())); + + CPPUNIT_ASSERT_MESSAGE + ( + "mkdtemp call failed", + out != nullptr + ); + + tmp_x += "/"; +#endif + tmp_x += TEST_PATH_POSTFIX; + + OUString tmpTestPath; + rc = osl::FileBase::getFileURLFromSystemPath(OStringToOUString(tmp_x, RTL_TEXTENCODING_UTF8), tmpTestPath); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "Cannot convert the system path back to a URL", + osl::FileBase::E_None, rc + ); + return tmpTestPath; + }(); + return test_path; + } + + static void rm_test_path(const OUString& path) + { + sal_Unicode buffer[PATH_BUFFER_SIZE]; + memcpy(buffer, path.getStr(), (path.getLength() + 1) * sizeof(sal_Unicode)); + + sal_Int32 i = rtl_ustr_lastIndexOfChar(buffer, '/'); + if (i == path.getLength()) + buffer[i] = 0; + + Directory::remove(OUString(buffer)); + + i = rtl_ustr_lastIndexOfChar(buffer, '/'); + assert(i != -1); + if (i != -1) + { + buffer[i] = 0; + Directory::remove(OUString(buffer)); + } + } + + namespace { + + class DirCreatedObserver : public DirectoryCreationObserver + { + public: + DirCreatedObserver() : i(0) {} + virtual void DirectoryCreated(const OUString&) override { i++; }; + + int number_of_dirs_created() const { return i; } + + private: + int i; + }; + + } + + class createPath : public CppUnit::TestFixture + { + public: + createPath() + {} + + void with_relative_path() + { + osl::FileBase::RC rc = Directory::createPath(TEST_PATH_POSTFIX); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_createDirectoryPath contract broken", + osl::FileBase::E_INVAL, rc + ); + } + + void without_callback() + { + OUString tp_url = get_test_path(); + + rm_test_path(tp_url); + + osl::FileBase::RC rc = Directory::createPath(tp_url); + + rm_test_path(tp_url); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_createDirectoryPath failed", + osl::FileBase::E_None, rc + ); + } + + void with_callback() + { + OUString tp_url = get_test_path(); + + rm_test_path(tp_url); + + DirCreatedObserver* observer = new DirCreatedObserver; + osl::FileBase::RC rc = Directory::createPath(tp_url, observer); + int nDirs = observer->number_of_dirs_created(); + delete observer; + + rm_test_path(tp_url); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_createDirectoryPath failed", + osl::FileBase::E_None, rc + ); + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createDirectoryPath failed", + nDirs > 0 + ); + + } + +#ifdef _WIN32 + + const char* get_unused_drive_letter() + { + static const char m_aBuff[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + DWORD ld = GetLogicalDrives(); + DWORD i = 4; + DWORD j = 2; + + while ((ld & i) && (i > 1)) + { i = i << 1; j++; } + + if (i > 2) + return m_aBuff + j; + + return nullptr; + } + + void at_invalid_logical_drive() + { + const char* drv = get_unused_drive_letter(); + char buff[PATH_BUFFER_SIZE]; + memset(buff, 0, sizeof(buff)); + + strncpy(buff, drv, 1); + strcat(buff, ":\\"); + strcat(buff, TEST_PATH_POSTFIX); + + OUString path = OUString::createFromAscii(buff); + OUString tp_url; + osl::FileBase::getFileURLFromSystemPath(path, tp_url); + + osl::FileBase::RC rc = Directory::createPath(tp_url); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createDirectoryPath doesn't fail on unused logical drive letters", + rc != osl::FileBase::E_None + ); + } +#endif /* _WIN32 */ + + CPPUNIT_TEST_SUITE(createPath); + CPPUNIT_TEST(with_relative_path); + CPPUNIT_TEST(without_callback); + CPPUNIT_TEST(with_callback); +#ifdef _WIN32 + CPPUNIT_TEST(at_invalid_logical_drive); +#endif + CPPUNIT_TEST_SUITE_END(); + + }; + + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::ctors); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::open); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::isOpen); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::close); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::reset); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::getNextItem); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::getVolumeInfo); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::create); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::remove); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Directory::createPath); +} + +#if 0 +#if defined UNX +/** get Current PID. +*/ +OUString getCurrentPID() +{ + //~ Get current PID and turn it into OUString; + int nPID = 0; +#ifdef _WIN32 + nPID = GetCurrentProcessId(); +#else + nPID = getpid(); +#endif + return OUString::number(nPID); +} +#endif +#endif + +namespace { + +//~ do some clean up work after all test completed. +class GlobalObject +{ +public: + ~GlobalObject() + { + try + { + //~ special clean up task in Windows and Unix separately; +#if (defined UNX) + //~ some clean up task for UNIX OS + ; +#else + //~ some clean up task for Windows OS + //~ check if some files are in the way, remove them if necessary. + if (ifFileExist(aTmpName6)) + deleteTestFile(aTmpName6); + if (ifFileExist(aTmpName4)) + deleteTestFile(aTmpName4); + if (checkDirectory(aTmpName4, oslCheckMode::Exist)) + deleteTestDirectory(aTmpName4); + if (ifFileExist(aTmpName3)) + deleteTestFile(aTmpName3); + if (checkDirectory(aTmpName3, oslCheckMode::Exist)) + deleteTestDirectory(aTmpName3); + + OUString aUStr(aUserDirectoryURL); + concatURL(aUStr, aHidURL1); + if (ifFileExist(aUStr)) + deleteTestFile(aUStr); + + OUString aUStr1(aRootURL); + concatURL(aUStr1, aTmpName2); + if (ifFileExist(aUStr1)) + deleteTestFile(aUStr1); +#endif + } + catch (const CppUnit::Exception &e) + { + printf("Exception caught in GlobalObject dtor(). Exception message: '%s'. Source line: %d\n", e.what(), e.sourceLine().lineNumber()); + } + catch (...) + { + printf("Exception caught (...) in GlobalObject dtor()\n"); + } + } +}; + +} + +static GlobalObject theGlobalObject; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/file/osl_File_Const.h b/sal/qa/osl/file/osl_File_Const.h new file mode 100644 index 0000000000..beee8d6d62 --- /dev/null +++ b/sal/qa/osl/file/osl_File_Const.h @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SAL_QA_OSL_FILE_OSL_FILE_CONST_H +#define INCLUDED_SAL_QA_OSL_FILE_OSL_FILE_CONST_H + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sal/types.h> + +#include <rtl/ustring.hxx> + +#include <cppunit/extensions/HelperMacros.h> + +static OUString getTempDirectoryURL_() +{ + OUString aDir; + CPPUNIT_ASSERT_EQUAL_MESSAGE("couldn't get system temp URL", + osl::FileBase::E_None, osl::FileBase::getTempDirURL(aDir)); + // This resolves symlinks in the temp path if any + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, + osl::FileBase::getAbsoluteFileURL(aDir, aDir, aDir)); + return aDir; +} + +static OUString getTempDirectorySys_() +{ + OUString aDir; + CPPUNIT_ASSERT_EQUAL_MESSAGE("couldn't get system temp directory", + osl::FileBase::E_None, osl::FileBase::getSystemPathFromFileURL(getTempDirectoryURL_(), aDir)); + return aDir; +} + +#ifdef __cplusplus +extern "C" +{ +#endif + +// common used string resource +// these common used string will be used as assist resource in test +// they are mostly OS independent, some of the resource can be reused +// so, a common test data repository will be better since it can be +// shared among all test code + +const char pBuffer_Char[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +const char pBuffer_Number[] = "1234567890"; +const char pBuffer_Blank[] = ""; + +// OS dependent/independent definitions/includes +// we use FILE_PREFIX for URL prefix, +// TEST_PLATFORM for test platform initial, +// TEST_PLATFORM_ROOT for root dir in comrresponding platform, +// TEST_PLATFORM_TEMP for temp dir in comrresponding platform, +// PATH_LIST_DELIMITER for separator of path list in comrresponding platform, +// PATH_SEPARATOR for separator in URL or system path in comrresponding platform, +// PATH_MAX/MAX_PATH for max path length in comrresponding platform, + +// OS independent const definition + +# define FILE_PREFIX "file:///" +# define TEST_FILE_SIZE 1024 + +// OS dependent declaration and includes + +#if ( defined UNX ) //Unix +# include <unistd.h> +# include <limits.h> +# include <math.h> +# include <errno.h> +# include <fcntl.h> +# include <sys/stat.h> +# if !defined(MACOSX) && !defined(IOS) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined (DRAGONFLY) && !defined(HAIKU) +# include <sys/statfs.h> +# else +# include <sys/param.h> +# ifndef HAIKU +# include <sys/mount.h> +# endif +# endif +# if !defined(ANDROID) +# include <sys/statvfs.h> +# endif +# include <sys/types.h> +# define TEST_PLATFORM_ROOT "/" +# define PATH_LIST_DELIMITER ":" +# define PATH_SEPARATOR "/" +#endif + +#if defined(_WIN32) // Windows +# include <io.h> +# define PATH_MAX MAX_PATH +# define TEST_PLATFORM_ROOT "c:/" +# define PATH_LIST_DELIMITER ";" +# define PATH_SEPARATOR "/" +#endif + +// OS independent file definition + +OUString aNullURL( "" ); +OUString aSlashURL( PATH_SEPARATOR ); +OUString aPreURL( FILE_PREFIX ); +OUString aRootURL( FILE_PREFIX TEST_PLATFORM_ROOT ); + +OUString aTempDirectorySys(getTempDirectorySys_()); +OUString aTempDirectoryURL(getTempDirectoryURL_()); +OUString aUserDirectorySys( aTempDirectorySys + "" ); +OUString aUserDirectoryURL( aTempDirectoryURL + "" ); + +// common used URL:temp, canonical, root, relative, link,etc + +OUString aCanURL1( aTempDirectoryURL + "/canonical.name" ); +OUString aCanURL2( + RTL_CONSTASCII_USTRINGPARAM("ca@#;+.,$///78no\0ni..name")); +OUString aCanURL3( "ca@#;+.,$//tmp/678nonical//name" ); +OUString aCanURL4( "canonical.name" ); +OUString aTmpName1( "tmpdir" ); +OUString aTmpName2( "tmpname" ); +OUString aTmpName3( aTempDirectoryURL + "/tmpdir" ); +OUString aTmpName4( aTempDirectoryURL + "/tmpdir/tmpname" ); +OUString aTmpName5( aTempDirectoryURL + "/tmpdir/../tmpdir/./tmpname" ); +OUString aTmpName6( aTempDirectoryURL + "/tmpname" ); +OUString aTmpName7( aTempDirectoryURL + "/noaccess" ); +OUString aTmpName8( aTempDirectoryURL + "/tmpname/tmpdir" ); +OUString aTmpName9( aTempDirectoryURL + "/tmpdir/../tmpdir/./" ); +OUString aTmpName10(aTempDirectoryURL + u"/\xE6\x9C\xAA\xE5\x91\xBD\xE5\x90\x8Dzhgb18030"); + +OUString aRelURL1( "relative/file1" ); +OUString aRelURL2( "relative/./file2" ); +OUString aRelURL3( "relative/../file3" ); +OUString aRelURL4( "././relative/../file4" ); +OUString aRelURL5( aTempDirectoryURL + "/./../" ); +OUString aLnkURL1( aTempDirectoryURL + "/link.file" ); +OUString aHidURL1( ".hiddenfile" ); + +// common used System Path:temp, root,etc + +OUString aRootSys( TEST_PLATFORM_ROOT ); +OUString aSysPath1( aTempDirectorySys + "/system.path" ); +OUString aSysPath2( aTempDirectorySys + "/system/path" ); +OUString aSysPath3( aTempDirectorySys + "/tmpdir" ); +OUString aSysPath4( aTempDirectorySys + "/tmpname" ); +OUString aSysPath5( aTempDirectorySys + u"/\xE6\x9C\xAA\xE5\x91\xBD\xE5\x90\x8Dzhgb18030" ); +OUString aSysPathLnk( aTempDirectorySys + "/link.file" ); +OUString aFifoSys( aTempDirectorySys + "/tmpdir/fifo" ); + +// FileType URL, we pick some canonical file in corresponding system for test: +// socket, link, etc. +// Note that this may be changed in the different platform, so be careful to use. + +#if ( defined UNX ) // Unix +OUString aTypeURL1( FILE_PREFIX "dev/ccv"); //socket Solaris/Linux +OUString aTypeURL2( FILE_PREFIX "devices/pseudo/tcp@0:tcp"); //special Solaris/Linux +OUString aTypeURL3( FILE_PREFIX "lib" ); //link Solaris +#else // Windows +OUString aTypeURL1( FILE_PREFIX "" ); +OUString aTypeURL2( FILE_PREFIX "" ); +OUString aTypeURL3( FILE_PREFIX "" ); +#endif + +// Volume device URL, we pick some canonical volume device for test: +// UNIX file system, Floppy Disk, Proc file system, Temp file system, Compact Disk. + +#if ( defined UNX ) // Unix +OUString aVolURL1( FILE_PREFIX ""); //ufs Solaris/Linux +#ifdef __sun +OUString aVolURL2( FILE_PREFIX "dev/fd" ); //fd Solaris +#else +OUString aVolURL2( FILE_PREFIX "dev/floppy/0u1440" ); //fd0 Linux +#endif +OUString aVolURL3( FILE_PREFIX "proc" ); //proc Solaris/Linux +OUString aVolURL4( FILE_PREFIX "staroffice" ); //nfs Solaris/Linux +OUString aVolURL5( FILE_PREFIX "tmp" ); //tmpfs Solaris +OUString aVolURL6( FILE_PREFIX "cdrom" ); //cd Solaris +#else // Windows +OUString aVolURL1( FILE_PREFIX "c:/" ); +OUString aVolURL2( FILE_PREFIX "a:/" ); +OUString aVolURL3( FILE_PREFIX "" ); +OUString aVolURL4( FILE_PREFIX "" ); +OUString aVolURL5( FILE_PREFIX "c:/temp" ); +OUString aVolURL6( FILE_PREFIX "e:/" ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // INCLUDED_SAL_QA_OSL_FILE_OSL_FILE_CONST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/file/osl_old_test_file.cxx b/sal/qa/osl/file/osl_old_test_file.cxx new file mode 100644 index 0000000000..bb37e8f338 --- /dev/null +++ b/sal/qa/osl/file/osl_old_test_file.cxx @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <osl/file.h> +#include <rtl/ustring.hxx> + +#ifdef SAL_UNX +#define TEST_VOLUME "" +#elif defined _WIN32 +#define TEST_VOLUME "Z:/" +#endif + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <utility> + +namespace osl_test_file +{ + +class oldtestfile : public CppUnit::TestFixture +{ +public: + void test_file_001(); + void test_file_002(); + void test_file_004(); + + CPPUNIT_TEST_SUITE( oldtestfile ); + CPPUNIT_TEST( test_file_001 ); + CPPUNIT_TEST( test_file_002 ); + CPPUNIT_TEST( test_file_004 ); + CPPUNIT_TEST_SUITE_END( ); +}; + +const std::pair<OUString, OUString> aSource1[] = { + { u"a"_ustr, u"file:///" TEST_VOLUME "bla/a"_ustr }, + ///TODO: check if last slash must be omitted in resolved path. +// { u"a/"_ustr, u"file:///" TEST_VOLUME "bla/a"_ustr }, + { u"../a"_ustr, u"file:///" TEST_VOLUME "a"_ustr }, + { u"a/.."_ustr, u"file:///" TEST_VOLUME "bla/"_ustr }, + { u"a/../b"_ustr, u"file:///" TEST_VOLUME "bla/b"_ustr }, + { u".."_ustr, u"file:///" TEST_VOLUME ""_ustr }, + { u"a/b/c/d"_ustr, u"file:///" TEST_VOLUME "bla/a/b/c/d"_ustr }, + { u"a/./c"_ustr, u"file:///" TEST_VOLUME "bla/a/c"_ustr }, + { u"a/././c"_ustr, u"file:///" TEST_VOLUME "bla/a/c"_ustr }, + { u"file:///" TEST_VOLUME "bla1/blub"_ustr, u"file:///" TEST_VOLUME "bla1/blub"_ustr }, +}; + +const std::pair<OUString, OUString> aSource2[] = { + { u"a"_ustr, u"file:///" TEST_VOLUME "bla/blubs/schnubbel/a"_ustr }, + ///TODO: check if last slash must be omitted in resolved path. +// { u"a/"_ustr, u"file:///" TEST_VOLUME "bla/blubs/schnubbel/a"_ustr }, + { u"../a"_ustr, u"file:///" TEST_VOLUME "bla/blubs/a"_ustr }, + { u"../../a"_ustr, u"file:///" TEST_VOLUME "bla/a"_ustr }, + { u"../../../a"_ustr, u"file:///" TEST_VOLUME "a"_ustr }, + { u"../../../a/b/c/d"_ustr, u"file:///" TEST_VOLUME "a/b/c/d"_ustr }, +}; + +void oldtestfile::test_file_001() +{ + OUString base1( "file:///" TEST_VOLUME "bla" ); + for (const auto& [rel, expected] : aSource1) + { + OUString target; + oslFileError e = osl_getAbsoluteFileURL( base1.pData, rel.pData , &target.pData ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("failure #1", osl_File_E_None, e ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("failure #1.1", expected, target); + } +} + +void oldtestfile::test_file_002() +{ + OUString base2( "file:///" TEST_VOLUME "bla/blubs/schnubbel" ); + for (const auto& [rel, expected] : aSource2) + { + OUString target; + oslFileError e = osl_getAbsoluteFileURL( base2.pData, rel.pData , &target.pData ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("failure #2", osl_File_E_None, e ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("failure #2.1", expected, target); + } +} + +void oldtestfile::test_file_004() +{ + OUString base4( "file:///" TEST_VOLUME "bla/" ); + for (const auto& [rel, expected] : aSource1) + { + OUString target; + oslFileError e = osl_getAbsoluteFileURL( base4.pData, rel.pData , &target.pData ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("failure #10", osl_File_E_None, e ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("failure #10.1", expected, target); + } +} + +} // namespace osl_test_file + +CPPUNIT_TEST_SUITE_REGISTRATION( osl_test_file::oldtestfile); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/file/test_cpy_wrt_file.cxx b/sal/qa/osl/file/test_cpy_wrt_file.cxx new file mode 100644 index 0000000000..8a8b7226fe --- /dev/null +++ b/sal/qa/osl/file/test_cpy_wrt_file.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <osl/file.hxx> +#include <rtl/ustring.hxx> + +using namespace osl; + +class test_osl_writeFile : public CppUnit::TestFixture +{ +public: + void wrt_file() + { + FileBase::RC err; + + //create a tempfile + OUString aTmpFile; + err = FileBase::createTempFile(nullptr, nullptr, &aTmpFile); + CPPUNIT_ASSERT_EQUAL_MESSAGE("temp File creation failed", osl::FileBase::E_None, err); + + //now attempt to open with Create flag an existing file, should get E_EXIST + File tmp_file(aTmpFile); + err = tmp_file.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); + + OString sErrorMsg = "Expected that '" + + OUStringToOString(aTmpFile, RTL_TEXTENCODING_ASCII_US) + + "' would exist!"; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sErrorMsg.getStr(), FileBase::E_EXIST, err); + + char buffer[1]; + sal_uInt64 written = 0; + err = tmp_file.write(static_cast<void*>(buffer), sizeof(buffer), written); + CPPUNIT_ASSERT_MESSAGE("write on unconnected file should fail", + err != osl::FileBase::E_None); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write on unconnected file should fail", + sal_uInt64(0), written); + + err = tmp_file.sync(); + CPPUNIT_ASSERT_MESSAGE("sync on unconnected file should fail", err != FileBase::E_None); + err = tmp_file.close(); + CPPUNIT_ASSERT_MESSAGE("close on unconnected file should fail", err != FileBase::E_None); + + err = ::osl::File::remove(aTmpFile); + CPPUNIT_ASSERT_EQUAL_MESSAGE("temp file should have existed", FileBase::E_None, err); + } + + CPPUNIT_TEST_SUITE(test_osl_writeFile); + CPPUNIT_TEST(wrt_file); + CPPUNIT_TEST_SUITE_END(); +}; + +// register test suites +CPPUNIT_TEST_SUITE_REGISTRATION(test_osl_writeFile); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/getsystempathfromfileurl/test-getsystempathfromfileurl.cxx b/sal/qa/osl/getsystempathfromfileurl/test-getsystempathfromfileurl.cxx new file mode 100644 index 0000000000..d4adff6531 --- /dev/null +++ b/sal/qa/osl/getsystempathfromfileurl/test-getsystempathfromfileurl.cxx @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <osl/file.hxx> + +#if defined(_WIN32) +#define MY_PATH_IN "/c:/foo/bar" +#define MY_PATH_OUT "c:\\foo\\bar" +#define MY_PATH_OUT_CONT MY_PATH_OUT "\\" +#define MY_PATH_OUT_REL "foo\\bar" +#else +#define MY_PATH_IN "/foo/bar" +#define MY_PATH_OUT MY_PATH_IN +#define MY_PATH_OUT_CONT MY_PATH_OUT "/" +#define MY_PATH_OUT_REL "foo/bar" +#endif + +namespace { + +class Test: public CppUnit::TestFixture { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testBadScheme); + CPPUNIT_TEST(testNoScheme); + CPPUNIT_TEST(testBadAuthority); + CPPUNIT_TEST(testLocalhost1Authority); + CPPUNIT_TEST(testLocalhost2Authority); + CPPUNIT_TEST(testLocalhost3Authority); + CPPUNIT_TEST(testNoAuthority); + CPPUNIT_TEST(testEmptyPath); + CPPUNIT_TEST(testHomeAbbreviation); + CPPUNIT_TEST(testOtherHomeAbbreviation); + CPPUNIT_TEST(testRelative); + CPPUNIT_TEST(testEscape); + CPPUNIT_TEST(testBadEscape2f); + CPPUNIT_TEST(testBadEscape2F); + CPPUNIT_TEST(testBad0); + CPPUNIT_TEST(testBadEscape0); + CPPUNIT_TEST(testBadQuery); + CPPUNIT_TEST(testBadFragment); + CPPUNIT_TEST_SUITE_END(); + + void testBadScheme(); + void testNoScheme(); + void testBadAuthority(); + void testLocalhost1Authority(); + void testLocalhost2Authority(); + void testLocalhost3Authority(); + void testNoAuthority(); + void testEmptyPath(); + void testHomeAbbreviation(); + void testOtherHomeAbbreviation(); + void testRelative(); + void testEscape(); + void testBadEscape2f(); + void testBadEscape2F(); + void testBad0(); + void testBadEscape0(); + void testBadQuery(); + void testBadFragment(); +}; + +void Test::testBadScheme() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL("foo:bar", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); + CPPUNIT_ASSERT_EQUAL(OUString(), p); +} + +void Test::testNoScheme() { +#if !defined(_WIN32) //TODO + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL("//" MY_PATH_IN, p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + CPPUNIT_ASSERT_EQUAL(OUString(MY_PATH_OUT), p); +#endif +} + +void Test::testBadAuthority() { +#if defined UNX + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://baz" MY_PATH_IN, p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); + CPPUNIT_ASSERT_EQUAL(OUString(), p); +#endif +} + +void Test::testLocalhost1Authority() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://localhost" MY_PATH_IN, p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + CPPUNIT_ASSERT_EQUAL(OUString(MY_PATH_OUT), p); +} + +void Test::testLocalhost2Authority() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://LOCALHOST" MY_PATH_IN, p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + CPPUNIT_ASSERT_EQUAL(OUString(MY_PATH_OUT), p); +} + +void Test::testLocalhost3Authority() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://127.0.0.1" MY_PATH_IN, p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + CPPUNIT_ASSERT_EQUAL(OUString(MY_PATH_OUT), p); +} + +void Test::testNoAuthority() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL("file:" MY_PATH_IN, p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + CPPUNIT_ASSERT_EQUAL(OUString(MY_PATH_OUT), p); +} + +void Test::testEmptyPath() { +#if defined UNX + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL("file://", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + CPPUNIT_ASSERT_EQUAL(OUString("/"), p); +#endif +} + +void Test::testHomeAbbreviation() { +#if defined UNX + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL("file:///~", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + // could theoretically fail due to osl::Security::getHomeDir problem + e = osl::FileBase::getSystemPathFromFileURL("file:///~/foo%2525/bar", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + // could theoretically fail due to osl::Security::getHomeDir problem + CPPUNIT_ASSERT(p.endsWith("/foo%25/bar")); +#endif +} + +void Test::testOtherHomeAbbreviation() { +#if defined UNX + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file:///~baz" MY_PATH_IN, p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); // not supported for now + CPPUNIT_ASSERT_EQUAL(OUString(), p); +#endif +} + +void Test::testRelative() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL("foo/bar", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + CPPUNIT_ASSERT(p.endsWith(MY_PATH_OUT_REL)); +} + +void Test::testEscape() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://" MY_PATH_IN "/b%61z", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e); + CPPUNIT_ASSERT_EQUAL(OUString(MY_PATH_OUT_CONT "baz"), p); +} + +void Test::testBadEscape2f() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://" MY_PATH_IN "/b%2fz", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); + CPPUNIT_ASSERT_EQUAL(OUString(), p); +} + +void Test::testBadEscape2F() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://" MY_PATH_IN "/b%2Fz", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); + CPPUNIT_ASSERT_EQUAL(OUString(), p); +} + +void Test::testBad0() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + OUString(RTL_CONSTASCII_USTRINGPARAM("file://" MY_PATH_IN "/b\x00z")), + p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); + CPPUNIT_ASSERT_EQUAL(OUString(), p); +} + +void Test::testBadEscape0() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://" MY_PATH_IN "/b%00z", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); + CPPUNIT_ASSERT_EQUAL(OUString(), p); +} + +void Test::testBadQuery() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://" MY_PATH_IN "?baz", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); + CPPUNIT_ASSERT_EQUAL(OUString(), p); +} + +void Test::testBadFragment() { + OUString p; + auto e = osl::FileBase::getSystemPathFromFileURL( + "file://" MY_PATH_IN "#baz", p); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_INVAL, e); + CPPUNIT_ASSERT_EQUAL(OUString(), p); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/module/osl_Module.cxx b/sal/qa/osl/module/osl_Module.cxx new file mode 100644 index 0000000000..f440a71516 --- /dev/null +++ b/sal/qa/osl/module/osl_Module.cxx @@ -0,0 +1,376 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// include files + +#include "osl_Module_Const.h" + +using namespace osl; + +/** get dll file URL. +*/ +static OUString getDllURL() +{ +#if defined(_WIN32) // lib in Unix and lib in Windows are not same in file name. + OUString libPath( "test_Module_DLL.dll" ); +#else + OUString libPath( "libtest_Module_DLL.so" ); +#endif + + OUString dirPath, dllPath; + osl::Module::getUrlFromAddress( + reinterpret_cast<oslGenericFunction>(&getDllURL), dirPath); + dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') + 1); + osl::FileBase::getAbsoluteFileURL( dirPath, libPath, dllPath ); + + return dllPath; +} + +namespace osl_Module +{ + namespace { + + /** class and member function that is available for module test : + */ + + class testClass + { + public: + static void myFunc() + { + printf("#Sun Microsystem\n"); + }; + }; + + } + + /** testing the methods: + Module(); + Module( const OUString& strModuleName, sal_Int32 nRtldMode = SAL_LOADMODULE_DEFAULT); + */ + class ctors : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void ctors_none( ) + { + ::osl::Module aMod; + bRes = aMod.is(); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor without parameter.", + !bRes ); + } + + void ctors_name_mode( ) + { + OUString aFileURL; + bRes = osl::Module::getUrlFromAddress( + reinterpret_cast<oslGenericFunction>( + &osl_Module::testClass::myFunc), + aFileURL); + + if ( !bRes ) + { + CPPUNIT_ASSERT_MESSAGE("Cannot locate current module.", false ); + } + + ::osl::Module aMod( aFileURL ); + bRes = aMod.is( ); + aMod.unload( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with load action.", + bRes ); + } + + CPPUNIT_TEST_SUITE( ctors ); + CPPUNIT_TEST( ctors_none ); + CPPUNIT_TEST( ctors_name_mode ); + CPPUNIT_TEST_SUITE_END( ); + }; // class ctors + + /** testing the methods: + static sal_Bool getUrlFromAddress(void * addr, OUString & libraryUrl) + */ + class getUrlFromAddress : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void getUrlFromAddress_001( ) + { + OUString aFileURL; + bRes = osl::Module::getUrlFromAddress( + reinterpret_cast<oslGenericFunction>( + &osl_Module::testClass::myFunc), + aFileURL); + if ( !bRes ) + { + CPPUNIT_ASSERT_MESSAGE("Cannot locate current module.", false ); + } + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test get Module URL from address.", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test get Module URL from address.", + 0 < aFileURL.lastIndexOf('/') ); + } + + void getUrlFromAddress_002( ) + { +#if !defined( MACOSX ) + // TODO: Find out why this fails on macOS + ::osl::Module aMod( getDllURL( ) ); + FuncPtr pFunc = reinterpret_cast<FuncPtr>(aMod.getSymbol( "firstfunc" )); + + OUString aFileURL; + bRes = osl::Module::getUrlFromAddress( + reinterpret_cast<oslGenericFunction>(pFunc), aFileURL); + if ( !bRes ) + { + CPPUNIT_ASSERT_MESSAGE("Cannot locate current module.", false ); + } + aMod.unload( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: load an external library, get its function address and get its URL.", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: load an external library, get its function address and get its URL.", + 0 < aFileURL.lastIndexOf('/') ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: load an external library, get its function address and get its URL.", + aFileURL.equalsIgnoreAsciiCase( getDllURL( ) ) ); +#endif + } + + /* tester comments: another case is getFunctionSymbol_001*/ + + CPPUNIT_TEST_SUITE( getUrlFromAddress ); + CPPUNIT_TEST( getUrlFromAddress_001 ); + CPPUNIT_TEST( getUrlFromAddress_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class getUrlFromAddress + + /** testing the method: + sal_Bool SAL_CALL load( const OUString& strModuleName, + sal_Int32 nRtldMode = SAL_LOADMODULE_DEFAULT) + */ + class load : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void load_001( ) + { + ::osl::Module aMod( getDllURL( ) ); + ::osl::Module aMod1; + + aMod1.load( getDllURL( ) ); + bRes = oslModule(aMod) == oslModule(aMod1); + aMod.unload( ); + aMod1.unload( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: load function should do the same thing as constructor with library name.", + bRes ); + } + + CPPUNIT_TEST_SUITE( load ); + CPPUNIT_TEST( load_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class load + + /** testing the method: + void SAL_CALL unload() + */ + class unload : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void unload_001( ) + { + ::osl::Module aMod( getDllURL( ) ); + + aMod.unload( ); + bRes = oslModule(aMod) ==nullptr; + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: unload function should do the same thing as destructor.", + bRes ); + } + + CPPUNIT_TEST_SUITE( unload ); + CPPUNIT_TEST( unload_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class unload + + /** testing the methods: + sal_Bool SAL_CALL is() const + */ + class is : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void is_001( ) + { + OUString aFileURL; + bRes = osl::Module::getUrlFromAddress( + reinterpret_cast<oslGenericFunction>( + osl_Module::testClass::myFunc), + aFileURL); + if ( !bRes ) + { + CPPUNIT_ASSERT_MESSAGE("Cannot locate current module - using executable instead", false ); + } + + ::osl::Module aMod; + bRes = aMod.is( ); + aMod.load( aFileURL ); + bRes1 = aMod.is( ); + aMod.unload( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test if a module is a loaded module.", + !bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test if a module is a loaded module.", + bRes1 ); + } + CPPUNIT_TEST_SUITE( is ); + CPPUNIT_TEST( is_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class is + + /** testing the methods: + void* SAL_CALL getSymbol( const OUString& strSymbolName) + */ + class getSymbol : public CppUnit::TestFixture + { + public: + bool bRes; + + void getSymbol_001( ) + { +#if !defined( MACOSX ) + // TODO: Find out why this fails on macOS + ::osl::Module aMod( getDllURL( ) ); + FuncPtr pFunc = reinterpret_cast<FuncPtr>(aMod.getSymbol( "firstfunc" )); + bRes = false; + if ( pFunc ) + bRes = pFunc( bRes ); + aMod.unload(); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: load a dll and call one function in it.", + bRes ); +#endif + } + + CPPUNIT_TEST_SUITE( getSymbol ); + CPPUNIT_TEST( getSymbol_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class getSymbol + + /** testing the methods: + operator oslModule() const + */ + class optr_oslModule : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void optr_oslModule_001( ) + { +#if !defined( MACOSX ) + // TODO: Find out why this fails on macOS + ::osl::Module aMod; + bRes = ( static_cast<oslModule>(aMod) == nullptr ); + + aMod.load( getDllURL( ) ); + bRes1 = static_cast<oslModule>(aMod) != nullptr; + + aMod.unload( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: the m_Module of a Module instance will be NULL when is not loaded, it will not be NULL after loaded.", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: the m_Module of a Module instance will be NULL when is not loaded, it will not be NULL after loaded.", + bRes1 ); +#endif + } + + void optr_oslModule_002( ) + { +#if !defined( MACOSX ) + // TODO: Find out why this fails on macOS + ::osl::Module aMod( getDllURL( ) ); + OUString funcName( "firstfunc" ); + + FuncPtr pFunc = reinterpret_cast<FuncPtr>(osl_getSymbol( static_cast<oslModule>(aMod), funcName.pData )); + bRes = false; + if ( pFunc ) + bRes = pFunc( bRes ); + + aMod.unload(); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: use m_Module to call osl_getSymbol() function.", + bRes ); +#endif + } + + CPPUNIT_TEST_SUITE( optr_oslModule ); + CPPUNIT_TEST( optr_oslModule_001 ); + CPPUNIT_TEST( optr_oslModule_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class optr_oslModule + + /** testing the methods: + oslGenericFunction SAL_CALL getFunctionSymbol( const OUString& ustrFunctionSymbolName ) + */ + class getFunctionSymbol : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void getFunctionSymbol_001( ) + { +#if !defined( MACOSX ) + // TODO: Find out why this fails on macOS + ::osl::Module aMod( getDllURL( ) ); + oslGenericFunction oslFunc = aMod.getFunctionSymbol( "firstfunc" ); + OUString aLibraryURL; + bRes = ::osl::Module::getUrlFromAddress( oslFunc, aLibraryURL); + aMod.unload(); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: load a dll and get its function addr and get its URL.", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: load a dll and get its function addr and get its URL.", + aLibraryURL.equalsIgnoreAsciiCase( getDllURL() ) ); +#endif + } + + CPPUNIT_TEST_SUITE( getFunctionSymbol ); + CPPUNIT_TEST( getFunctionSymbol_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class getFunctionSymbol + +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::ctors); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::getUrlFromAddress); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::load); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::unload); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::is); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::getSymbol); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::optr_oslModule); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::getFunctionSymbol); + +} // namespace osl_Module + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/module/osl_Module_Const.h b/sal/qa/osl/module/osl_Module_Const.h new file mode 100644 index 0000000000..3434d439f2 --- /dev/null +++ b/sal/qa/osl/module/osl_Module_Const.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SAL_QA_OSL_MODULE_OSL_MODULE_CONST_H +#define INCLUDED_SAL_QA_OSL_MODULE_OSL_MODULE_CONST_H + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <osl/module.hxx> +#include <osl/file.hxx> + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#if defined(UNX) // Unix +# include <unistd.h> +#elif defined(_WIN32) // Windows +# include <io.h> +#endif + +# define FILE_PREFIX "file:///" + +// function pointer type. + +typedef sal_Bool (* FuncPtr )( sal_Bool ); + +#endif // INCLUDED_SAL_QA_OSL_MODULE_OSL_MODULE_CONST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/module/osl_Module_DLL.cxx b/sal/qa/osl/module/osl_Module_DLL.cxx new file mode 100644 index 0000000000..9222e2ec4f --- /dev/null +++ b/sal/qa/osl/module/osl_Module_DLL.cxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> + +#include <cppunit/plugin/TestPlugIn.h> + +// This module contains no tests. It is loaded as a dynamic library by +// osl_Module. +// But we instantiate a test plugin to fake the build process. +CPPUNIT_PLUGIN_IMPLEMENT(); + +extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool firstfunc(sal_Bool) { return true; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/mutex/osl_Mutex.cxx b/sal/qa/osl/mutex/osl_Mutex.cxx new file mode 100644 index 0000000000..440532d09b --- /dev/null +++ b/sal/qa/osl/mutex/osl_Mutex.cxx @@ -0,0 +1,908 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// include files + +#include <sal/types.h> +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <osl/thread.hxx> +#include <osl/mutex.hxx> + +#define BUFFER_SIZE 16 + +using namespace osl; + +/** pause nSec seconds helper function. +*/ +namespace ThreadHelper +{ + static void thread_sleep_tenth_sec(sal_uInt32 _nTenthSec) + { + osl::Thread::wait(std::chrono::milliseconds(_nTenthSec * 100)); + } + static void thread_sleep( sal_uInt32 _nSec ) + { + /// print statement in thread process must use fflush() to force display. + // t_print("# wait %d seconds. ", _nSec ); + fflush(stdout); + + thread_sleep_tenth_sec( _nSec * 10 ); + // printf("# done\n" ); + } +} + +// Beginning of the test cases for osl_Mutex class + +namespace { + +/** mutually exclusive data +*/ +struct resource { + sal_Int32 data1; + sal_Int32 data2; + Mutex lock; +}; + +/** IncreaseThread provide data. +*/ +class IncreaseThread : public Thread +{ +public: + explicit IncreaseThread( struct resource *pData ): pResource( pData ) { } + + virtual ~IncreaseThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#IncreaseThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + struct resource *pResource; + + void SAL_CALL run( ) override + { + pResource->lock.acquire( ); + for( sal_Int8 i = 0; i < 3; i++ ) + { + pResource->data1++; + yield( ); //yield() give CPU time to other thread, other thread if not block, they will change the data; + } + if ( pResource->data2 == 0 ) + pResource->data2 = ( pResource->data1 > 0 ? pResource->data1 : 0 - pResource->data1 ); + pResource->lock.release(); + } +}; + +/** DecreaseThread consume data. +*/ +class DecreaseThread : public Thread +{ +public: + explicit DecreaseThread( struct resource *pData ): pResource( pData ) { } + + virtual ~DecreaseThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#DecreaseThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + struct resource *pResource; + + void SAL_CALL run( ) override + { + pResource->lock.acquire( ); + for( sal_Int8 i = 0; i < 3; i++ ) + { + pResource->data1--; + yield( ); //yield() give CPU time to other thread, other thread if not block, they will change the data; + } + if ( pResource->data2 == 0 ) + pResource->data2 = ( pResource->data1 > 0 ? pResource->data1 : 0 - pResource->data1 ); + pResource->lock.release(); + } +}; + +/** chain structure used in Threads as critical resource +*/ +struct chain { + sal_Int32 buffer[ BUFFER_SIZE ]; + Mutex lock; + sal_Int8 pos; +}; + +/** PutThread write to the chain structure in a mutex manner. +*/ +class PutThread : public Thread +{ +public: + //get the struct pointer to write data to buffer + explicit PutThread( struct chain* pData ): pChain( pData ) { } + + virtual ~PutThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#PutThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + struct chain* pChain; + + void SAL_CALL run( ) override + { + //block here if the mutex has been acquired + pChain->lock.acquire( ); + + //current position in buffer to write + sal_Int8 nPos = pChain->pos; + oslThreadIdentifier oId = getIdentifier( ); + //write data + sal_Int8 i; + for ( i = 0; i < 5; i++ ) + { + pChain->buffer[ nPos + i ] = oId; + yield( ); + } + //revise the position + pChain->pos = nPos + i; + + //finish writing, release the mutex + pChain->lock.release(); + } +}; + +/** thread for testing Mutex acquire. + */ +class HoldThread : public Thread +{ +public: + //get the Mutex pointer to operate + explicit HoldThread( Mutex* pMutex ): pMyMutex( pMutex ) { } + + virtual ~HoldThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#HoldThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + Mutex* pMyMutex; + + void SAL_CALL run() override + { + // block here if the mutex has been acquired + pMyMutex->acquire( ); + printf("# Mutex acquired. \n" ); + pMyMutex->release( ); + } +}; + +class WaitThread : public Thread +{ +public: + //get the Mutex pointer to operate + explicit WaitThread( Mutex* pMutex ): pMyMutex( pMutex ) { } + + virtual ~WaitThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#WaitThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + Mutex* pMyMutex; + + void SAL_CALL run( ) override + { + // block here if the mutex has been acquired + pMyMutex->acquire( ); + ThreadHelper::thread_sleep_tenth_sec( 2 ); + pMyMutex->release( ); + } +}; + +/** thread for testing getGlobalMutex. + */ +class GlobalMutexThread : public Thread +{ +public: + //get the Mutex pointer to operate + GlobalMutexThread( ){ } + + virtual ~GlobalMutexThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#GlobalMutexThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + void SAL_CALL run( ) override + { + // block here if the mutex has been acquired + Mutex* pGlobalMutex; + pGlobalMutex = Mutex::getGlobalMutex( ); + pGlobalMutex->acquire( ); + printf("# Global Mutex acquired. \n" ); + pGlobalMutex->release( ); + } +}; + +} + +namespace osl_Mutex +{ + + /** Test of the osl::Mutex::constructor + */ + class ctor : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + struct chain m_Data; + struct resource m_Res; + + void setUp( ) override + { + for ( sal_Int8 i=0; i < BUFFER_SIZE; i++ ) + m_Data.buffer[i] = 0; + m_Data.pos = 0; + + m_Res.data1 = 0; + m_Res.data2 = 0; + } + + /** Create two threads to write data to the same buffer, use Mutex to assure + during one thread write data five times, the other thread should not begin writing. + the two threads wrote two different data: their thread ID, so we can check the data + in buffer to know the order of the two threads writing + */ + void ctor_001() + { + PutThread myThread1( &m_Data ); + PutThread myThread2( &m_Data ); + + myThread1.create( ); + myThread2.create( ); + + //wait until the two threads terminate + myThread1.join( ); + myThread2.join( ); + + bool bRes = false; + + // every 5 data should the same + // LLA: this is not a good check, it's too fix + if (m_Data.buffer[0] == m_Data.buffer[1] && + m_Data.buffer[1] == m_Data.buffer[2] && + m_Data.buffer[2] == m_Data.buffer[3] && + m_Data.buffer[3] == m_Data.buffer[4] && + m_Data.buffer[5] == m_Data.buffer[6] && + m_Data.buffer[6] == m_Data.buffer[7] && + m_Data.buffer[7] == m_Data.buffer[8] && + m_Data.buffer[8] == m_Data.buffer[9]) + bRes = true; + + /*for (sal_Int8 i=0; i<BUFFER_SIZE; i++) + printf("#data in buffer is %d\n", m_Data.buffer[i]); + */ + + CPPUNIT_ASSERT_MESSAGE("Mutex ctor", bRes); + + } + + /** Create two threads to write data to operate on the same number , use Mutex to assure, + one thread increase data 3 times, the other thread decrease 3 times, store the operate + result when the first thread complete, if it is interrupt by the other thread, the stored + number will not be 3. + */ + void ctor_002() + { + IncreaseThread myThread1( &m_Res ); + DecreaseThread myThread2( &m_Res ); + + myThread1.create( ); + myThread2.create( ); + + //wait until the two threads terminate + myThread1.join( ); + myThread2.join( ); + + bool bRes = false; + + // every 5 data should the same + if ( ( m_Res.data1 == 0 ) && ( m_Res.data2 == 3 ) ) + bRes = true; + + CPPUNIT_ASSERT_MESSAGE( "test Mutex ctor function: increase and decrease a number 3 times without interrupt.", bRes ); + } + + CPPUNIT_TEST_SUITE( ctor ); + CPPUNIT_TEST( ctor_001 ); + CPPUNIT_TEST( ctor_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class ctor + + /** Test of the osl::Mutex::acquire method + */ + class acquire : public CppUnit::TestFixture + { + public: + // acquire mutex in main thread, and then call acquire again in myThread, + // the child thread should block, wait 2 secs, it still block. + // Then release mutex in main thread, the child thread could return from acquire, + // and go to exec next statement, so could terminate quickly. + void acquire_001( ) + { + Mutex aMutex; + //acquire here + bool bRes = aMutex.acquire( ); + // pass the pointer of mutex to child thread + HoldThread myThread( &aMutex ); + myThread.create( ); + + ThreadHelper::thread_sleep_tenth_sec( 2 ); + // if acquire in myThread does not work, 2 secs is long enough, + // myThread should terminate now, and bRes1 should be sal_False + bool bRes1 = myThread.isRunning( ); + + aMutex.release( ); + ThreadHelper::thread_sleep_tenth_sec( 1 ); + // after release mutex, myThread stops blocking and will terminate immediately + bool bRes2 = myThread.isRunning( ); + myThread.join( ); + + CPPUNIT_ASSERT_MESSAGE( "Mutex acquire", bRes ); + CPPUNIT_ASSERT_MESSAGE( "Mutex acquire", bRes1 ); + CPPUNIT_ASSERT_MESSAGE( "Mutex acquire", !bRes2 ); + } + + //in the same thread, acquire twice should success + void acquire_002() + { + Mutex aMutex; + //acquire here + bool bRes = aMutex.acquire(); + bool bRes1 = aMutex.acquire(); + + bool bRes2 = aMutex.tryToAcquire(); + + aMutex.release(); + + CPPUNIT_ASSERT_MESSAGE("Mutex acquire", bRes); + CPPUNIT_ASSERT_MESSAGE("Mutex acquire", bRes1); + CPPUNIT_ASSERT_MESSAGE("Mutex acquire", bRes2); + + } + + CPPUNIT_TEST_SUITE( acquire ); + CPPUNIT_TEST( acquire_001 ); + CPPUNIT_TEST( acquire_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class acquire + + /** Test of the osl::Mutex::tryToAcquire method + */ + class tryToAcquire : public CppUnit::TestFixture + { + public: + // First let child thread acquire the mutex, and wait 2 secs, during the 2 secs, + // in main thread, tryToAcquire mutex should return False + // then after the child thread terminated, tryToAcquire should return True + void tryToAcquire_001() + { + Mutex aMutex; + WaitThread myThread(&aMutex); + myThread.create(); + + // ensure the child thread acquire the mutex + ThreadHelper::thread_sleep_tenth_sec(1); + + bool bRes1 = aMutex.tryToAcquire(); + + if (bRes1) + aMutex.release(); + // wait the child thread terminate + myThread.join(); + + bool bRes2 = aMutex.tryToAcquire(); + + if (bRes2) + aMutex.release(); + + CPPUNIT_ASSERT_MESSAGE("Try to acquire Mutex", !bRes1); + CPPUNIT_ASSERT_MESSAGE("Try to acquire Mutex", bRes2); + } + + CPPUNIT_TEST_SUITE(tryToAcquire); + CPPUNIT_TEST(tryToAcquire_001); + CPPUNIT_TEST_SUITE_END(); + }; // class tryToAcquire + + /** Test of the osl::Mutex::release method + */ + class release : public CppUnit::TestFixture + { + public: + /** acquire/release are not used in pairs: after child thread acquired mutex, + the main thread release it, then any thread could acquire it. + */ + void release_001() + { + Mutex aMutex; + WaitThread myThread( &aMutex ); + myThread.create( ); + + // ensure the child thread acquire the mutex + ThreadHelper::thread_sleep_tenth_sec( 1 ); + + bool bRunning = myThread.isRunning( ); + bool bRes1 = aMutex.tryToAcquire( ); + // wait the child thread terminate + myThread.join( ); + + bool bRes2 = aMutex.tryToAcquire( ); + + if ( bRes2 ) + aMutex.release( ); + + CPPUNIT_ASSERT_MESSAGE( "release Mutex: try to acquire before and after the mutex has been released", + !bRes1 ); + CPPUNIT_ASSERT_MESSAGE( "release Mutex: try to acquire before and after the mutex has been released", + bRes2 ); + CPPUNIT_ASSERT_MESSAGE( "release Mutex: try to acquire before and after the mutex has been released", + bRunning ); + + } + + // how about release twice? + void release_002() + { + } + + CPPUNIT_TEST_SUITE( release ); + CPPUNIT_TEST( release_001 ); + CPPUNIT_TEST( release_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class release + + /** Test of the osl::Mutex::getGlobalMutex method + */ + class getGlobalMutex : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + void getGlobalMutex_001() + { + Mutex* pGlobalMutex; + pGlobalMutex = Mutex::getGlobalMutex(); + pGlobalMutex->acquire(); + + GlobalMutexThread myThread; + myThread.create(); + + ThreadHelper::thread_sleep_tenth_sec(1); + bool bRes1 = myThread.isRunning(); + + pGlobalMutex->release(); + ThreadHelper::thread_sleep_tenth_sec(1); + // after release mutex, myThread stops blocking and will terminate immediately + bool bRes2 = myThread.isRunning(); + + CPPUNIT_ASSERT_MESSAGE("Global Mutex works", bRes1); + CPPUNIT_ASSERT_MESSAGE("Global Mutex works", !bRes2); + } + + void getGlobalMutex_002( ) + { + bool bRes; + + Mutex *pGlobalMutex; + pGlobalMutex = Mutex::getGlobalMutex( ); + pGlobalMutex->acquire( ); + { + Mutex *pGlobalMutex1; + pGlobalMutex1 = Mutex::getGlobalMutex( ); + bRes = pGlobalMutex1->release( ); + } + + CPPUNIT_ASSERT_MESSAGE( "Global Mutex works: if the code between {} get the different mutex as the former one, it will return false when release.", + bRes ); + } + + CPPUNIT_TEST_SUITE(getGlobalMutex); + CPPUNIT_TEST(getGlobalMutex_001); + CPPUNIT_TEST(getGlobalMutex_002); + CPPUNIT_TEST_SUITE_END(); + }; // class getGlobalMutex + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::ctor, "osl_Mutex"); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::acquire, "osl_Mutex"); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::tryToAcquire, "osl_Mutex"); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::release, "osl_Mutex"); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::getGlobalMutex, "osl_Mutex"); +} // namespace osl_Mutex + +// Beginning of the test cases for osl_Guard class + +namespace { + +class GuardThread : public Thread +{ +public: + //get the Mutex pointer to operate + explicit GuardThread( Mutex* pMutex ): pMyMutex( pMutex ) { } + + virtual ~GuardThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#GuardThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + Mutex* pMyMutex; + + void SAL_CALL run( ) override + { + // block here if the mutex has been acquired + MutexGuard aGuard( pMyMutex ); + ThreadHelper::thread_sleep_tenth_sec( 2 ); + } +}; + +} + +namespace osl_Guard +{ + class ctor : public CppUnit::TestFixture + { + public: + // insert your test code here. + void ctor_001() + { + Mutex aMutex; + GuardThread myThread(&aMutex); + myThread.create(); + + ThreadHelper::thread_sleep_tenth_sec(1); + bool bRes = aMutex.tryToAcquire(); + // after 1 second, the mutex has been guarded, and the child thread should be running + bool bRes1 = myThread.isRunning(); + + myThread.join(); + bool bRes2 = aMutex.tryToAcquire(); + + CPPUNIT_ASSERT_MESSAGE("GuardThread constructor", + !bRes); + CPPUNIT_ASSERT_MESSAGE("GuardThread constructor", + bRes1); + CPPUNIT_ASSERT_MESSAGE("GuardThread constructor", + bRes2); + } + + void ctor_002( ) + { + Mutex aMutex; + + /// use reference constructor here + MutexGuard myGuard( aMutex ); + + /// the GuardThread will block here when it is initialised. + GuardThread myThread( &aMutex ); + myThread.create( ); + + /// is it still blocking? + ThreadHelper::thread_sleep_tenth_sec( 2 ); + bool bRes = myThread.isRunning( ); + + /// oh, release him. + aMutex.release( ); + myThread.join( ); + + CPPUNIT_ASSERT_MESSAGE("GuardThread constructor: reference initialization, acquire the mutex before running the thread, then check if it is blocking.", + bRes); + } + + CPPUNIT_TEST_SUITE(ctor); + CPPUNIT_TEST(ctor_001); + CPPUNIT_TEST(ctor_002); + CPPUNIT_TEST_SUITE_END(); + }; // class ctor + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Guard::ctor, "osl_Guard"); +} // namespace osl_Guard + +// Beginning of the test cases for osl_ClearableGuard class + +namespace { + +/** Thread for test ClearableGuard + */ +class ClearGuardThread : public Thread +{ +public: + //get the Mutex pointer to operate + explicit ClearGuardThread( Mutex* pMutex ): pMyMutex( pMutex ) {} + + virtual ~ClearGuardThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#ClearGuardThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + Mutex* pMyMutex; + + void SAL_CALL run( ) override + { + // acquire the mutex + // printf("# ClearGuardThread" ); + ClearableMutexGuard aGuard( pMyMutex ); + ThreadHelper::thread_sleep( 5 ); + + // release the mutex + aGuard.clear( ); + ThreadHelper::thread_sleep( 2 ); + } +}; + +} + +namespace osl_ClearableGuard +{ + + class ctor : public CppUnit::TestFixture + { + public: + void ctor_001() + { + Mutex aMutex; + + /// now, the aMutex has been guarded. + ClearableMutexGuard myMutexGuard( &aMutex ); + + /// it will return sal_False if the aMutex has not been Guarded. + bool bRes = aMutex.release( ); + + CPPUNIT_ASSERT_MESSAGE("ClearableMutexGuard constructor, test the acquire operation when initialized.", + bRes); + } + + void ctor_002( ) + { + Mutex aMutex; + + /// now, the aMutex has been guarded, this time, we use reference constructor. + ClearableMutexGuard myMutexGuard( aMutex ); + + /// it will return sal_False if the aMutex has not been Guarded. + bool bRes = aMutex.release( ); + + CPPUNIT_ASSERT_MESSAGE("ClearableMutexGuard constructor, test the acquire operation when initialized, we use reference constructor this time.", + bRes); + } + + CPPUNIT_TEST_SUITE(ctor); + CPPUNIT_TEST(ctor_001); + CPPUNIT_TEST(ctor_002); + CPPUNIT_TEST_SUITE_END(); + }; // class ctor + + class clear : public CppUnit::TestFixture + { + public: + void clear_001() + { + Mutex aMutex; + ClearGuardThread myThread(&aMutex); + myThread.create(); + + TimeValue aTimeVal_befor; + osl_getSystemTime( &aTimeVal_befor ); + // wait 1 second to assure the child thread has begun + ThreadHelper::thread_sleep(1); + + while (true) + { + if (aMutex.tryToAcquire()) + { + break; + } + ThreadHelper::thread_sleep(1); + } + TimeValue aTimeVal_after; + osl_getSystemTime( &aTimeVal_after ); + sal_Int32 nSec = aTimeVal_after.Seconds - aTimeVal_befor.Seconds; + printf("nSec is %" SAL_PRIdINT32 "\n", nSec); + + myThread.join(); + + CPPUNIT_ASSERT_MESSAGE("ClearableGuard method: clear", + nSec < 7); + CPPUNIT_ASSERT_MESSAGE("ClearableGuard method: clear", + nSec > 1); + } + + void clear_002( ) + { + Mutex aMutex; + + /// now, the aMutex has been guarded. + ClearableMutexGuard myMutexGuard( &aMutex ); + + /// launch the HoldThread, it will be blocked here. + HoldThread myThread( &aMutex ); + myThread.create( ); + + /// is it blocking? + ThreadHelper::thread_sleep_tenth_sec( 4 ); + bool bRes = myThread.isRunning( ); + + /// use clear to release. + myMutexGuard.clear( ); + myThread.join( ); + bool bRes1 = myThread.isRunning( ); + + CPPUNIT_ASSERT_MESSAGE( "ClearableGuard method: clear, control the HoldThread's running status!", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "ClearableGuard method: clear, control the HoldThread's running status!", + !bRes1 ); + } + + CPPUNIT_TEST_SUITE( clear ); + CPPUNIT_TEST( clear_001 ); + CPPUNIT_TEST( clear_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class clear + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( osl_ClearableGuard::ctor, "osl_ClearableGuard" ); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( osl_ClearableGuard::clear, "osl_ClearableGuard" ); +} // namespace osl_ClearableGuard + +// Beginning of the test cases for osl_ResettableGuard class + +namespace { + +/** Thread for test ResettableGuard + */ +class ResetGuardThread : public Thread +{ +public: + //get the Mutex pointer to operate + explicit ResetGuardThread( Mutex* pMutex ): pMyMutex( pMutex ) {} + + virtual ~ResetGuardThread( ) override + { + CPPUNIT_ASSERT_MESSAGE( "#ResetGuardThread does not shutdown properly.\n", !isRunning( ) ); + } +protected: + Mutex* pMyMutex; + + void SAL_CALL run( ) override + { + // acquire the mutex + printf("# ResettableGuard\n" ); + ResettableMutexGuard aGuard( pMyMutex ); + // release the mutex + aGuard.clear( ); + ThreadHelper::thread_sleep_tenth_sec( 2 ); + } +}; + +} + +namespace osl_ResettableGuard +{ + class ctor : public CppUnit::TestFixture + { + public: + void ctor_001() + { + Mutex aMutex; + + /// now, the aMutex has been guarded. + ResettableMutexGuard myMutexGuard( &aMutex ); + + /// it will return sal_False if the aMutex has not been Guarded. + bool bRes = aMutex.release( ); + + CPPUNIT_ASSERT_MESSAGE("ResettableMutexGuard constructor, test the acquire operation when initialized.", + bRes); + + aMutex.acquire(); + } + + void ctor_002( ) + { + Mutex aMutex; + + /// now, the aMutex has been guarded, this time, we use reference constructor. + ResettableMutexGuard myMutexGuard( aMutex ); + + /// it will return sal_False if the aMutex has not been Guarded. + bool bRes = aMutex.release( ); + + CPPUNIT_ASSERT_MESSAGE( "ResettableMutexGuard constructor, test the acquire operation when initialized, we use reference constructor this time.", + bRes); + + aMutex.acquire(); + } + + CPPUNIT_TEST_SUITE(ctor); + CPPUNIT_TEST(ctor_001); + CPPUNIT_TEST(ctor_002); + CPPUNIT_TEST_SUITE_END(); + }; // class ctor + + class reset : public CppUnit::TestFixture + { + public: + void reset_001( ) + { + Mutex aMutex; + ResetGuardThread myThread( &aMutex ); + ResettableMutexGuard myMutexGuard( aMutex ); + myThread.create( ); + + /// is it running? and clear done? + bool bRes = myThread.isRunning( ); + myMutexGuard.clear( ); + ThreadHelper::thread_sleep_tenth_sec( 1 ); + + /// if reset is not success, the release will return sal_False + myMutexGuard.reset( ); + bool bRes1 = aMutex.release( ); + myThread.join( ); + + CPPUNIT_ASSERT_MESSAGE( "ResettableMutexGuard method: reset", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "ResettableMutexGuard method: reset", + bRes1 ); + + aMutex.acquire(); + } + +#ifdef LINUX + void reset_002( ) + { + Mutex aMutex; + ResettableMutexGuard myMutexGuard( &aMutex ); + + /// shouldn't release after clear; + myMutexGuard.clear( ); + aMutex.acquire(); + bool bRes = aMutex.release( ); + + /// can release after reset. + myMutexGuard.reset( ); + bool bRes1 = aMutex.release( ); + + CPPUNIT_ASSERT_MESSAGE( "ResettableMutexGuard method: reset, release after clear and reset, on Solaris, the mutex can be release without acquire, so it can not passed on (SOLARIS), but not the reason for reset_002", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "ResettableMutexGuard method: reset, release after clear and reset, on Solaris, the mutex can be release without acquire, so it can not passed on (SOLARIS), but not the reason for reset_002", + bRes1 ); + + aMutex.acquire(); + } +#endif + + CPPUNIT_TEST_SUITE(reset); + CPPUNIT_TEST(reset_001); +#ifdef LINUX + CPPUNIT_TEST(reset_002); +#endif + CPPUNIT_TEST_SUITE_END(); + }; // class reset + +CPPUNIT_TEST_SUITE_REGISTRATION(osl_ResettableGuard::ctor); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_ResettableGuard::reset); +} // namespace osl_ResettableGuard + +// The following sets variables for GNU EMACS +// Local Variables: +// tab-width:4 +// End: + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/pipe/osl_Pipe.cxx b/sal/qa/osl/pipe/osl_Pipe.cxx new file mode 100644 index 0000000000..62463f8868 --- /dev/null +++ b/sal/qa/osl/pipe/osl_Pipe.cxx @@ -0,0 +1,889 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// include files + +#include <sal/types.h> +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <rtl/ustring.hxx> + +#include <osl/test/uniquepipename.hxx> +#include <osl/thread.hxx> + +#include <osl/pipe.hxx> + +#include <string.h> + +using namespace osl; + +/** print last error of pipe system. + */ +static void printPipeError( ::osl::Pipe const & aPipe ) +{ + oslPipeError nError = aPipe.getError( ); + printf("#printPipeError# " ); + switch ( nError ) { + case osl_Pipe_E_None: + printf("Success!\n" ); + break; + case osl_Pipe_E_NotFound: + printf("The returned error is: Not found!\n" ); + break; + case osl_Pipe_E_AlreadyExists: + printf("The returned error is: Already exist!\n" ); + break; + case osl_Pipe_E_NoProtocol: + printf("The returned error is: No protocol!\n" ); + break; + case osl_Pipe_E_NetworkReset: + printf("The returned error is: Network reset!\n" ); + break; + case osl_Pipe_E_ConnectionAbort: + printf("The returned error is: Connection aborted!\n" ); + break; + case osl_Pipe_E_ConnectionReset: + printf("The returned error is: Connection reset!\n" ); + break; + case osl_Pipe_E_NoBufferSpace: + printf("The returned error is: No buffer space!\n" ); + break; + case osl_Pipe_E_TimedOut: + printf("The returned error is: Timeout!\n" ); + break; + case osl_Pipe_E_ConnectionRefused: + printf("The returned error is: Connection refused!\n" ); + break; + case osl_Pipe_E_invalidError: + printf("The returned error is: Invalid error!\n" ); + break; + default: + printf("The returned error is: Number %d, Unknown Error\n", nError ); + break; + } +} + +// pipe name and transfer contents + +constexpr OUString aTestPipeName(u"testpipe2"_ustr); +constexpr OUString aTestPipe1(u"testpipe1"_ustr); + +constexpr OString m_pTestString1("Sun Microsystems"_ostr); +constexpr OString m_pTestString2("test pipe PASS/OK"_ostr); + +// test code start here + +namespace osl_Pipe +{ + +// most return value -1 denote a fail of operation. + +#define OSL_PIPE_FAIL -1 + + /** testing the methods: + inline Pipe(); + inline Pipe(const OUString& strName, oslPipeOptions Options); + inline Pipe(const OUString& strName, oslPipeOptions Options,const Security & rSecurity); + inline Pipe(const Pipe& pipe); + inline Pipe(oslPipe pipe, __sal_NoAcquire noacquire ); + inline Pipe(oslPipe Pipe); + */ + class ctors : public CppUnit::TestFixture + { + public: + bool bRes, bRes1, bRes2; + + void ctors_none( ) + { + ::osl::Pipe aPipe; + bRes = aPipe.is( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with no parameter, yet no case to test.", + !bRes ); + } + + void ctors_name_option( ) + { + /// create a named pipe. + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + ::osl::Pipe aAssignPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_OPEN ); + + bRes = aPipe.is( ) && aAssignPipe.is( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with name and option.", + bRes ); + } + + void ctors_name_option_security( ) + { + /// create a security pipe. + const ::osl::Security rSecurity; + ::osl::Pipe aSecurityPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE, rSecurity ); + + bRes = aSecurityPipe.is( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with name, option and security, the test of security is not implemented yet.", + bRes ); + } + + void ctors_copy( ) + { + /// create a pipe. + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + /// create a pipe using copy constructor. + ::osl::Pipe aCopyPipe( aPipe ); + + bRes = aCopyPipe.is( ) && aCopyPipe == aPipe; + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test copy constructor.", + bRes ); + } + + /* Note: DO NOT DO THIS - I have very deliberately caused send to FAIL, *on purpose* as this is the + only sane way to test noacquire. This is a terrible misuse of no-acquire, but in this case is + needed only so we can test to make sure no-acquire is working! + */ + void ctors_no_acquire( ) + { + /// create a pipe. + OUString aPipeName(test::uniquePipeName(aTestPipeName)); + oslPipe handle(osl_createPipe(aPipeName.pData, osl_Pipe_CREATE, nullptr)); + /// constructs a pipe reference without acquiring the handle. + std::unique_ptr<osl::Pipe> xNoAcquirePipe(new osl::Pipe(handle, SAL_NO_ACQUIRE)); + + StreamPipe aStreamPipe(handle); + xNoAcquirePipe.reset(); + int nRet = aStreamPipe.send("a", 1); + + if (nRet >= 0) + bRes = false; + else + bRes = true; + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with no acquire of handle, deleted nonacquired pipe but could still send on original pipe!.", + bRes ); + } + + void ctors_acquire( ) + { + /// create a base pipe. + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + /// constructs two pipes, the second acquires the first pipe's handle. + ::osl::Pipe aAcquirePipe( aPipe.getHandle( ) ); + ::osl::Pipe aAcquirePipe1( nullptr ); + + bRes = aAcquirePipe.is(); + bRes1 = aAcquirePipe1.is(); + bRes2 = aPipe == aAcquirePipe; + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with acquire of handle, original pipe does not exist.", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with acquire of handle, copied pipe does not exist", + !bRes1 ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test pipes should have same handle", bRes2); + } + + CPPUNIT_TEST_SUITE( ctors ); + CPPUNIT_TEST( ctors_none ); + CPPUNIT_TEST( ctors_name_option ); + CPPUNIT_TEST( ctors_name_option_security ); + CPPUNIT_TEST( ctors_copy ); + CPPUNIT_TEST( ctors_no_acquire ); + CPPUNIT_TEST( ctors_acquire ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the method: + inline sal_Bool SAL_CALL is() const; + */ + class is : public CppUnit::TestFixture + { + public: + void is_001( ) + { + ::osl::Pipe aPipe; + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test is(), check if the pipe is a valid one.", !aPipe.is( ) ); + } + + void is_002( ) + { + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test is(), a normal pipe creation.", aPipe.is( ) ); + } + + void is_003( ) + { + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test is(), an invalid case.", !aPipe.is( ) ); + } + + void is_004( ) + { + ::osl::Pipe aPipe( nullptr ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test is(), an invalid constructor.", !aPipe.is( ) ); + } + + CPPUNIT_TEST_SUITE( is ); + CPPUNIT_TEST( is_001 ); + CPPUNIT_TEST( is_002 ); + CPPUNIT_TEST( is_003 ); + CPPUNIT_TEST( is_004 ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the methods: + inline sal_Bool create( const OUString & strName, + oslPipeOptions Options, const Security &rSec ); + nline sal_Bool create( const OUString & strName, + oslPipeOptions Options = osl_Pipe_OPEN ); + */ + class create : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + /** tester comment: + + security create only be tested creation, security section is + untested yet. + */ + + void create_named_security_001( ) + { + const Security rSec; + ::osl::Pipe aPipe; + bRes = aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE, rSec ); + bRes1 = aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE, rSec ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test creation.", + bRes); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test creation.", + !bRes1); + } + + void create_named_security_002( ) + { + const Security rSec; + ::osl::Pipe aPipe, aPipe1; + bRes = aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE, rSec ); + bRes1 = aPipe1.create( test::uniquePipeName(aTestPipeName), osl_Pipe_OPEN, rSec ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test creation and open.", + bRes); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test creation and open.", + bRes1); + } + + void create_named_001( ) + { + ::osl::Pipe aPipe; + bRes = aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + bRes1 = aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test creation.", + bRes); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test creation.", + !bRes1); + } + + void create_named_002( ) + { + ::osl::Pipe aPipe, aPipe1; + bRes = aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + bRes1 = aPipe1.create( test::uniquePipeName(aTestPipeName) ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test creation and open.", + bRes); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test creation and open.", + bRes1); + } + + void create_named_003( ) + { + ::osl::Pipe aPipe; + bRes = aPipe.create( test::uniquePipeName(aTestPipeName) ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test default option is open.", + !bRes ); + } + + CPPUNIT_TEST_SUITE( create ); + CPPUNIT_TEST( create_named_security_001 ); + CPPUNIT_TEST( create_named_security_002 ); + CPPUNIT_TEST( create_named_001 ); + CPPUNIT_TEST( create_named_002 ); + CPPUNIT_TEST( create_named_003 ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the method: + inline void SAL_CALL clear(); + */ + class clear : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void clear_001( ) + { + ::osl::Pipe aPipe; + aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + aPipe.clear( ); + bRes = aPipe.is( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test clear.", + !bRes ); + } + + CPPUNIT_TEST_SUITE( clear ); + CPPUNIT_TEST( clear_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the methods: + inline Pipe& SAL_CALL operator= (const Pipe& pipe); + inline Pipe& SAL_CALL operator= (const oslPipe pipe ); + */ + class assign : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void assign_ref( ) + { + ::osl::Pipe aPipe, aPipe1; + aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + aPipe1 = aPipe; + bRes = aPipe1.is( ); + bRes1 = aPipe == aPipe1; + aPipe.close( ); + aPipe1.close( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test assign with reference.", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test assign with reference.", + bRes1 ); + } + + void assign_handle( ) + { + ::osl::Pipe aPipe, aPipe1; + aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + aPipe1 = aPipe.getHandle( ); + bRes = aPipe1.is( ); + bRes1 = aPipe == aPipe1; + aPipe.close( ); + aPipe1.close( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test assign with handle.", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test assign with handle.", + bRes1 ); + } + + CPPUNIT_TEST_SUITE( assign ); + CPPUNIT_TEST( assign_ref ); + CPPUNIT_TEST( assign_handle ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the method: + inline sal_Bool SAL_CALL isValid() const; + isValid( ) has not been implemented under the following platforms, please refer to osl/pipe.hxx + */ + + /** testing the method: + inline sal_Bool SAL_CALL operator==( const Pipe& rPipe ) const; + */ + class isEqual : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void isEqual_001( ) + { + ::osl::Pipe aPipe; + aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + bRes = aPipe == aPipe; // NOLINT(misc-redundant-expression) + aPipe.close( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test isEqual(), compare itself.", + bRes ); + } + + void isEqual_002( ) + { + ::osl::Pipe aPipe, aPipe1, aPipe2; + aPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + + aPipe1 = aPipe; + aPipe2.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + + bRes = aPipe == aPipe1; + bRes1 = aPipe == aPipe2; + aPipe.close( ); + aPipe1.close( ); + aPipe2.close( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test isEqual(),create one copy instance, and compare.", + bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test isEqual(),create one copy instance, and compare.", + !bRes1 ); + } + + CPPUNIT_TEST_SUITE( isEqual ); + CPPUNIT_TEST( isEqual_001 ); + CPPUNIT_TEST( isEqual_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the method: + inline void SAL_CALL close(); + */ + class close : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void close_001( ) + { + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipe1), osl_Pipe_CREATE ); + aPipe.close( ); + bRes = aPipe.is( ); + + aPipe.clear( ); + bRes1 = aPipe.is( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: difference between close and clear.", + bRes); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: difference between close and clear.", + !bRes1); + } + + void close_002( ) + { + ::osl::StreamPipe aPipe( test::uniquePipeName(aTestPipe1), osl_Pipe_CREATE ); + aPipe.close( ); + int nRet = aPipe.send( m_pTestString1.getStr(), 3 ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "#test comment#: use after close.", + OSL_PIPE_FAIL, nRet ); + } + + CPPUNIT_TEST_SUITE( close ); + CPPUNIT_TEST( close_001 ); + CPPUNIT_TEST( close_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the method: + inline oslPipeError SAL_CALL accept(StreamPipe& Connection); + please refer to StreamPipe::recv + */ + + /** testing the method: + inline oslPipeError SAL_CALL getError() const; + */ + class getError : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void getError_001( ) + { + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_OPEN ); + oslPipeError nError = aPipe.getError( ); + printPipeError( aPipe ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: open a non-exist pipe.", + nError != osl_Pipe_E_None ); + } + + void getError_002( ) + { + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + ::osl::Pipe aPipe1( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + oslPipeError nError = aPipe.getError( ); + printPipeError( aPipe ); + aPipe.clear( ); + aPipe1.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: create an already exist pipe.", + nError != osl_Pipe_E_None ); + } + + CPPUNIT_TEST_SUITE( getError ); + CPPUNIT_TEST( getError_001 ); + CPPUNIT_TEST( getError_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the method: + inline oslPipe SAL_CALL getHandle() const; + */ + class getHandle : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void getHandle_equalityOperatorAgainstSelf( ) + { + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_OPEN ); + bRes = aPipe == aPipe.getHandle( ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: one pipe should equal to its handle.", + bRes ); + } + + void getHandle_equalityOperatorAgainstDerivedPipe( ) + { + ::osl::Pipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + ::osl::Pipe aPipe1( aPipe.getHandle( ) ); + bRes = aPipe == aPipe1; + aPipe.clear( ); + aPipe1.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: one pipe derived from another pipe's handle.", + bRes ); + } + + CPPUNIT_TEST_SUITE( getHandle ); + CPPUNIT_TEST( getHandle_equalityOperatorAgainstSelf ); + CPPUNIT_TEST( getHandle_equalityOperatorAgainstDerivedPipe ); + CPPUNIT_TEST_SUITE_END( ); + }; + + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::ctors); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::is); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::create); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::clear); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::assign); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::isEqual); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::close); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::getError); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_Pipe::getHandle); + +} // namespace osl_Pipe + +namespace osl_StreamPipe +{ + + /** testing the methods: + inline StreamPipe(); + inline StreamPipe(oslPipe Pipe); + inline StreamPipe(const StreamPipe& Pipe); + inline StreamPipe(const OUString& strName, oslPipeOptions Options = osl_Pipe_OPEN); + inline StreamPipe(const OUString& strName, oslPipeOptions Options, const Security &rSec ); + inline StreamPipe( oslPipe pipe, __sal_NoAcquire noacquire ); + */ + class ctors : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void ctors_none( ) + { + // create a pipe. + ::osl::StreamPipe aStreamPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + // create an unattached pipe. + ::osl::StreamPipe aStreamPipe1; + bRes = aStreamPipe1.is( ); + + // assign it and check. + aStreamPipe1 = aStreamPipe; + bRes1 = aStreamPipe1.is( ); + aStreamPipe.clear( ); + aStreamPipe1.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with no parameter, before and after assign.", + !bRes ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with no parameter, before and after assign.", + bRes1 ); + } + + void ctors_handle( ) + { + // create a pipe. + ::osl::StreamPipe aStreamPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + // create a pipe with last handle. + ::osl::StreamPipe aStreamPipe1( aStreamPipe.getHandle( ) ); + bRes = aStreamPipe1.is( ) && aStreamPipe == aStreamPipe1; + aStreamPipe.clear( ); + aStreamPipe1.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with other's handle.", + bRes ); + } + + void ctors_copy( ) + { + // create a pipe. + ::osl::StreamPipe aStreamPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + // create an unattached pipe. + ::osl::StreamPipe aStreamPipe1( aStreamPipe ); + bRes = aStreamPipe1.is( ) && aStreamPipe == aStreamPipe1; + aStreamPipe.clear( ); + aStreamPipe1.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test copy constructor.", + bRes ); + } + + void ctors_name_option( ) + { + // create a pipe. + ::osl::StreamPipe aStreamPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + // create an unattached pipe. + ::osl::StreamPipe aStreamPipe1( test::uniquePipeName(aTestPipeName), osl_Pipe_OPEN ); + bRes = aStreamPipe1.is( ) && aStreamPipe.is( ); + aStreamPipe.clear( ); + aStreamPipe1.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with name and option.", + bRes ); + } + + void ctors_name_option_security( ) + { + /// create a security pipe. + const ::osl::Security rSecurity; + ::osl::StreamPipe aSecurityPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE, rSecurity ); + + bRes = aSecurityPipe.is( ); + aSecurityPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with name, option and security, the test of security is not implemented yet.", + bRes ); + } + + /** tester comment: + + When test the following constructor, don't know how to test the + acquire and no acquire action. possible plans: + 1.release one handle and check the other( did not success since the + other still exist and valid. ) + 2. release one handle twice to see getLastError( )(the getLastError + always returns invalidError(LINUX)). + */ + + void ctors_no_acquire( ) + { + // create a pipe. + ::osl::StreamPipe aPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + osl_acquirePipe(aPipe.getHandle()); + // constructs a pipe reference without acquiring the handle. + ::osl::StreamPipe aNoAcquirePipe( aPipe.getHandle( ), SAL_NO_ACQUIRE ); + + bRes = aNoAcquirePipe.is( ); + aPipe.clear( ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with no acquire of handle, only validation test, do not know how to test no acquire.", + bRes ); + } + + CPPUNIT_TEST_SUITE( ctors ); + CPPUNIT_TEST( ctors_none ); + CPPUNIT_TEST( ctors_handle ); + CPPUNIT_TEST( ctors_copy ); + CPPUNIT_TEST( ctors_name_option ); + CPPUNIT_TEST( ctors_name_option_security ); + CPPUNIT_TEST( ctors_no_acquire ); + CPPUNIT_TEST_SUITE_END( ); + }; + + /** testing the methods: + inline StreamPipe & SAL_CALL operator=(oslPipe Pipe); + inline StreamPipe& SAL_CALL operator=(const Pipe& pipe); + mindy: not implemented in osl/pipe.hxx, so remove the cases + */ + + /** wait _nSec seconds. + */ + static void thread_sleep( sal_uInt32 _nSec ) + { + /// print statement in thread process must use fflush() to force display. + fflush(stdout); + + osl::Thread::wait(std::chrono::seconds(_nSec)); + } + // test read/write & send/recv data to pipe + + namespace { + + class Pipe_DataSink_Thread : public Thread + { + public: + char buf[256]; + Pipe_DataSink_Thread( ) { } + + protected: + void SAL_CALL run( ) override + { + printf("open pipe\n"); + ::osl::StreamPipe aSenderPipe( test::uniquePipeName(aTestPipeName), osl_Pipe_OPEN ); // test::uniquePipeName(aTestPipeName) is a string = "TestPipe" + if ( !aSenderPipe.is() ) + { + printf("pipe open failed! \n"); + } + else + { + printf("read\n"); + sal_Int32 nChars = aSenderPipe.read( buf, m_pTestString1.getLength() + 1 ); + if ( nChars < 0 ) + { + printf("read failed! \n"); + return; + } + buf[sizeof(buf)-1] = '\0'; + printf("buffer is %s \n", buf); + printf("send\n"); + nChars = aSenderPipe.send( m_pTestString2.getStr(), m_pTestString2.getLength() + 1 ); + if ( nChars < 0 ) + { + printf("client send failed! \n"); + return; + } + } + } + + }; + + class Pipe_DataSource_Thread : public Thread + { + public: + char buf[256]; + ::osl::Pipe aListenPipe; + ::osl::StreamPipe aConnectionPipe; + Pipe_DataSource_Thread( ) + { + printf("create pipe\n"); + aListenPipe.create( test::uniquePipeName(aTestPipeName), osl_Pipe_CREATE ); + } + virtual ~Pipe_DataSource_Thread( ) override + { + aListenPipe.close(); + } + protected: + void SAL_CALL run( ) override + { + //create pipe. + printf("listen\n"); + if ( !aListenPipe.is() ) + { + printf("pipe create failed! \n"); + } + else + { + //start server and wait for connection. + printf("accept\n"); + if ( aListenPipe.accept( aConnectionPipe ) != osl_Pipe_E_None ) + { + printf("pipe accept failed!"); + return; + } + printf("write\n"); + // write to pipe + sal_Int32 nChars = aConnectionPipe.write( m_pTestString1.getStr(), m_pTestString1.getLength() + 1 ); + if ( nChars < 0) + { + printf("server write failed! \n"); + return; + } + printf("recv\n"); + nChars = aConnectionPipe.recv( buf, 256 ); + + if ( nChars < 0) + { + printf("server receive failed! \n"); + return; + } + buf[sizeof(buf)-1] = '\0'; + printf("received message is: %s\n", buf ); + } + } + }; + + } + + /** testing the method: read/write/send/recv and Pipe::accept + */ + class recv : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void recv_001( ) + { + //launch threads. + Pipe_DataSource_Thread myDataSourceThread; + Pipe_DataSink_Thread myDataSinkThread; + myDataSourceThread.create( ); + thread_sleep( 1 ); + myDataSinkThread.create( ); + + //wait until the thread terminate + myDataSinkThread.join( ); + myDataSourceThread.join( ); + + int nCompare1 = strcmp( myDataSinkThread.buf, m_pTestString1.getStr() ); + int nCompare2 = strcmp( myDataSourceThread.buf, m_pTestString2.getStr() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "test send/recv/write/read.", 0, nCompare1 ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "test send/recv/write/read.", 0, nCompare2 ); + } + //close pipe when accept + void recv_002() + { + thread_sleep( 1 ); + + Pipe_DataSource_Thread myDataSourceThread; + Pipe_DataSink_Thread myDataSinkThread; + myDataSourceThread.create( ); + thread_sleep( 1 ); + myDataSourceThread.aListenPipe.close(); + myDataSourceThread.join( ); + //no condition judgment here, if the case could finish executing within 1 or 2 seconds, it passes. + } + + CPPUNIT_TEST_SUITE( recv ); + CPPUNIT_TEST( recv_001 ); + CPPUNIT_TEST( recv_002 ); + CPPUNIT_TEST_SUITE_END( ); + }; + + CPPUNIT_TEST_SUITE_REGISTRATION(osl_StreamPipe::ctors); +//CPPUNIT_TEST_SUITE_REGISTRATION(osl_StreamPipe::assign); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_StreamPipe::recv); + +} // namespace osl_StreamPipe + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/process/batch.bat b/sal/qa/osl/process/batch.bat new file mode 100755 index 0000000000..e27f7191bf --- /dev/null +++ b/sal/qa/osl/process/batch.bat @@ -0,0 +1,19 @@ +rem +rem This file is part of the LibreOffice project. +rem +rem This Source Code Form is subject to the terms of the Mozilla Public +rem License, v. 2.0. If a copy of the MPL was not distributed with this +rem file, You can obtain one at http://mozilla.org/MPL/2.0/. +rem +rem This file incorporates work covered by the following license notice: +rem +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed +rem with this work for additional information regarding copyright +rem ownership. The ASF licenses this file to you under the Apache +rem License, Version 2.0 (the "License"); you may not use this file +rem except in compliance with the License. You may obtain a copy of +rem the License at http://www.apache.org/licenses/LICENSE-2.0 . +rem +@echo off +echo "Hello world"
\ No newline at end of file diff --git a/sal/qa/osl/process/batch.sh b/sal/qa/osl/process/batch.sh new file mode 100755 index 0000000000..fd3828c6ae --- /dev/null +++ b/sal/qa/osl/process/batch.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo "Hello world"
\ No newline at end of file diff --git a/sal/qa/osl/process/osl_Thread.cxx b/sal/qa/osl/process/osl_Thread.cxx new file mode 100644 index 0000000000..0cb0e773db --- /dev/null +++ b/sal/qa/osl/process/osl_Thread.cxx @@ -0,0 +1,2000 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <algorithm> +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#endif + +// include files + +#include <sal/types.h> +#include <rtl/string.hxx> +#include <osl/thread.hxx> +#include <osl/mutex.hxx> +#include <osl/time.h> + +#include <string.h> +#include <memory> + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#define t_print printf + +using namespace osl; + +namespace { + +// Small stopwatch +class StopWatch { + TimeValue t1,t2; // Start and stoptime + +protected: + sal_Int32 m_nNanoSec; + sal_Int32 m_nSeconds; + + bool m_bIsValid; // TRUE, when started and stopped + bool m_bIsRunning; // TRUE, when started + +public: + StopWatch(); + + void start(); // Starts time + void stop(); // Stops time + + double getSeconds() const; + double getTenthSec() const; +}; + +} + +// ================================= Stop Watch ================================= + +// A small stopwatch for internal use +// (c) Lars Langhans 29.12.1996 22:10 + +StopWatch::StopWatch() + : m_nNanoSec(0) + , m_nSeconds(0) + , m_bIsValid(false) + , m_bIsRunning(false) +{ + t1.Seconds = 0; + t1.Nanosec = 0; + t2.Seconds = 0; + t2.Nanosec = 0; +} + +void StopWatch::start() +{ +// pre: % +// post: Start Timer + + m_bIsValid = false; + m_bIsRunning = true; + osl_getSystemTime( &t1 ); + t_print("# %u %u nsecs\n", static_cast<unsigned>(t1.Seconds), static_cast<unsigned>(t1.Nanosec)); + // gettimeofday(&t1, 0); +} + +void StopWatch::stop() +{ +// pre: Timer should be started +// post: Timer will stopped + + osl_getSystemTime( &t2 ); + t_print("# %u %u nsecs\n", static_cast<unsigned>(t2.Seconds), static_cast<unsigned>(t2.Nanosec)); + + if (m_bIsRunning) + { // check if started. + m_nSeconds = static_cast<sal_Int32>(t2.Seconds) - static_cast<sal_Int32>(t1.Seconds); + if ( t2.Nanosec > t1.Nanosec ) + m_nNanoSec = static_cast<sal_Int32>(t2.Nanosec) - static_cast<sal_Int32>(t1.Nanosec); + else + { + m_nNanoSec = 1000000000 + static_cast<sal_Int32>(t2.Nanosec) - static_cast<sal_Int32>(t1.Nanosec); + m_nSeconds -= 1; + } + t_print("# %u %u nsecs\n", static_cast<unsigned>(m_nSeconds), static_cast<unsigned>(m_nNanoSec) ); + m_bIsValid = true; + m_bIsRunning = false; + } +} + +double StopWatch::getSeconds() const +{ +// pre: valid = TRUE +// BACK: time in seconds + + double nValue = 0.0; + if (m_bIsValid) + { + nValue = double(m_nNanoSec) / 1000000000.0 + m_nSeconds; // milli micro nano + } + return nValue; +} + +double StopWatch::getTenthSec() const +{ + double nValue = 0.0; + if (m_bIsValid) + { + nValue = double(m_nNanoSec) / 100000000.0 + m_nSeconds * 10; + } + return nValue ; +} + +namespace { + +template <class T> +class ThreadSafeValue +{ + T m_nFlag; + Mutex m_aMutex; +public: + explicit ThreadSafeValue(T n = 0): m_nFlag(n) {} + T getValue() + { + //block if already acquired by another thread. + osl::MutexGuard g(m_aMutex); + return m_nFlag; + } + void incValue() + { + //only one thread operate on the flag. + osl::MutexGuard g(m_aMutex); + m_nFlag++; + } + void acquire() {m_aMutex.acquire();} + void release() {m_aMutex.release();} +}; + +} + +namespace ThreadHelper +{ + static void thread_sleep_tenth_sec(sal_Int32 _nTenthSec) + { + osl::Thread::wait(std::chrono::milliseconds(_nTenthSec * 100)); + } + + static void outputPriority(oslThreadPriority const& _aPriority) + { + // LLA: output the priority + if (_aPriority == osl_Thread_PriorityHighest) + { + t_print("Prio is High\n"); + } + else if (_aPriority == osl_Thread_PriorityAboveNormal) + { + t_print("Prio is above normal\n"); + } + else if (_aPriority == osl_Thread_PriorityNormal) + { + t_print("Prio is normal\n"); + } + else if (_aPriority == osl_Thread_PriorityBelowNormal) + { + t_print("Prio is below normal\n"); + } + else if (_aPriority == osl_Thread_PriorityLowest) + { + t_print("Prio is lowest\n"); + } + else + { + t_print("Prio is unknown\n"); + } + } +} + +namespace { + +/** Simple thread for testing Thread-create. + + Just add 1 of value 0, and after running, result is 1. + */ +class myThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + sal_Int32 getValue() { return m_aFlag.getValue(); } +protected: + /** guarded value which initialized 0 + + @see ThreadSafeValue + */ + void SAL_CALL run() override + { + while(schedule()) + { + m_aFlag.incValue(); + ThreadHelper::thread_sleep_tenth_sec(1); + } + } + +public: + + virtual void SAL_CALL suspend() override + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } + + virtual ~myThread() override + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } + +}; + +/** Thread which has a flag add 1 every second until 20 + */ +class OCountThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + OCountThread() : m_nWaitSec(0) + { + t_print("new OCountThread thread %u!\n", static_cast<unsigned>(getIdentifier())); + } + sal_Int32 getValue() { return m_aFlag.getValue(); } + + void setWait(sal_Int32 nSec) + { + m_nWaitSec = nSec; + //m_bWait = sal_True; + } + + virtual void SAL_CALL suspend() override + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } + +protected: + //sal_Bool m_bWait; + sal_Int32 m_nWaitSec; + + void SAL_CALL run() override + { + /// if the thread should terminate, schedule return false + while (m_aFlag.getValue() < 20 && schedule()) + { + m_aFlag.incValue(); + ThreadHelper::thread_sleep_tenth_sec(1); + + if (m_nWaitSec != 0) + { + TimeValue nTV; + nTV.Seconds = m_nWaitSec / 10 ; + nTV.Nanosec = ( m_nWaitSec%10 ) * 100000000 ; + wait( nTV ); + m_nWaitSec = 0; + } + } + } + void SAL_CALL onTerminated() override + { + t_print("normally terminate this thread %u!\n", static_cast<unsigned>(getIdentifier())); + } +public: + + virtual ~OCountThread() override + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } + +}; + +/** no call schedule in the run method +*/ +class ONoScheduleThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + sal_Int32 getValue() { return m_aFlag.getValue(); } + + virtual void SAL_CALL suspend() override + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } +protected: + void SAL_CALL run() override + { + while (m_aFlag.getValue() < 10) + { + m_aFlag.incValue(); + ThreadHelper::thread_sleep_tenth_sec(1); + } + } + void SAL_CALL onTerminated() override + { + t_print("normally terminate this thread %u!\n", static_cast<unsigned>(getIdentifier())); + } +public: + ONoScheduleThread() + { + t_print("new thread id %u!\n", static_cast<unsigned>(getIdentifier())); + } + virtual ~ONoScheduleThread() override + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } + +}; + + +class OAddThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + //oslThreadIdentifier m_id, m_CurId; + OAddThread(){} + sal_Int32 getValue() { return m_aFlag.getValue(); } + + virtual void SAL_CALL suspend() override + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } +protected: + void SAL_CALL run() override + { + //if the thread should terminate, schedule return false + while (schedule()) + { + m_aFlag.incValue(); + } + } + void SAL_CALL onTerminated() override + { + // t_print("normally terminate this thread %d!\n", getIdentifier()); + } +public: + + virtual ~OAddThread() override + { + if (isRunning()) + { + // t_print("error: not terminated.\n"); + } + } + +}; + +} + +namespace osl_Thread +{ + + static void resumeAndWaitThread(Thread* _pThread) + { + // This function starts a thread, wait a second and suspends the thread + // Due to the fact, that a suspend and never run thread never really exists. + + // Note: on UNX, after createSuspended, and then terminate the thread, it performs well; + // while on Windows, after createSuspended, the thread can not terminate, wait endlessly, + // so here call resume at first, then call terminate. +#ifdef _WIN32 + t_print("resumeAndWaitThread\n"); + _pThread->resume(); + ThreadHelper::thread_sleep_tenth_sec(1); +#else + _pThread->resume(); +#endif + } + + // kill a running thread and join it, if it has terminated, do nothing + static void termAndJoinThread(Thread* _pThread) + { + _pThread->terminate(); + +// LLA: Windows feature???, a suspended thread can not terminated, so we have to weak it up +#ifdef _WIN32 + _pThread->resume(); + ThreadHelper::thread_sleep_tenth_sec(1); +#endif + t_print("#wait for join.\n"); + _pThread->join(); + } +/** Test of the osl::Thread::create method + */ + + class create : public CppUnit::TestFixture + { + public: + /** Simple create a thread. + + Create a simple thread, it just does add 1 to value(which initialized 0), + if the thread run, the value should be 1. + */ + void create_001() + { + myThread* newthread = new myThread; + bool bRes = newthread->create(); + CPPUNIT_ASSERT_MESSAGE("Can not creates a new thread!\n", bRes); + + ThreadHelper::thread_sleep_tenth_sec(1); // wait short + bool isRunning = newthread->isRunning(); // check if thread is running + /// wait for the new thread to assure it has run + ThreadHelper::thread_sleep_tenth_sec(3); + sal_Int32 nValue = newthread->getValue(); + /// to assure the new thread has terminated + termAndJoinThread(newthread); + delete newthread; + + t_print(" nValue = %d\n", static_cast<int>(nValue)); + t_print("isRunning = %s\n", isRunning ? "true" : "false"); + + CPPUNIT_ASSERT_MESSAGE( + "Creates a new thread", + nValue >= 1 + ); + CPPUNIT_ASSERT_MESSAGE( + "Creates a new thread", + isRunning + ); + + } + + /** only one running thread per instance, return false if create secondly + */ + void create_002() + { + myThread* newthread = new myThread; + bool res1 = newthread->create(); + bool res2 = newthread->create(); + t_print("In non pro, an assertion should occurred. This behaviour is right.\n"); + termAndJoinThread(newthread); + delete newthread; + + CPPUNIT_ASSERT_MESSAGE( + "Creates a new thread: can not create two threads per instance", + res1 + ); + CPPUNIT_ASSERT_MESSAGE( + "Creates a new thread: can not create two threads per instance", + !res2 + ); + + } + + CPPUNIT_TEST_SUITE(create); + CPPUNIT_TEST(create_001); + CPPUNIT_TEST(create_002); + CPPUNIT_TEST_SUITE_END(); + }; // class create + + /** Test of the osl::Thread::createSuspended method + */ + class createSuspended : public CppUnit::TestFixture + { + public: + /** Create a suspended thread, use the same class as create_001 + + after create, wait enough time, check the value, if it's still the initial value, pass + */ + void createSuspended_001() + { + myThread* newthread = new myThread; + bool bRes = newthread->createSuspended(); + CPPUNIT_ASSERT_MESSAGE("Can not creates a new thread!", bRes); + + ThreadHelper::thread_sleep_tenth_sec(1); + bool isRunning = newthread->isRunning(); + ThreadHelper::thread_sleep_tenth_sec(3); + sal_Int32 nValue = newthread->getValue(); + + resumeAndWaitThread(newthread); + + termAndJoinThread(newthread); + delete newthread; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Creates a new suspended thread", + sal_Int32(0), nValue + ); + CPPUNIT_ASSERT_MESSAGE( + "Creates a new suspended thread", + isRunning + ); + } + + void createSuspended_002() + { + myThread* newthread = new myThread; + bool res1 = newthread->createSuspended(); + bool res2 = newthread->createSuspended(); + + resumeAndWaitThread(newthread); + + termAndJoinThread(newthread); + + delete newthread; + + CPPUNIT_ASSERT_MESSAGE( + "Creates a new thread: can not create two threads per instance", + res1 + ); + CPPUNIT_ASSERT_MESSAGE( + "Creates a new thread: can not create two threads per instance", + !res2 + ); + } + + CPPUNIT_TEST_SUITE(createSuspended); + CPPUNIT_TEST(createSuspended_001); + // LLA: Deadlocked!!! + CPPUNIT_TEST(createSuspended_002); + CPPUNIT_TEST_SUITE_END(); + }; // class createSuspended + + /** when the count value equal to or more than 3, suspend the thread. + */ + static void suspendCountThread(OCountThread* _pCountThread) + { + sal_Int32 nValue = 0; + while (true) + { + nValue = _pCountThread->getValue(); + if (nValue >= 3) + { + _pCountThread->suspend(); + break; + } + } + } + + /** Test of the osl::Thread::suspend method + */ + class suspend : public CppUnit::TestFixture + { + public: + /** Use a thread which has a flag added 1 every second + + ALGORITHM: + create the thread, after running special time, record value of flag, then suspend it, + wait a long time, check the flag, if it remains unchanged during suspending + */ + void suspend_001() + { + OCountThread* aCountThread = new OCountThread(); + bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + // the thread run for some seconds, but not terminate + suspendCountThread( aCountThread ); + + // the value just after calling suspend + sal_Int32 nValue = aCountThread->getValue(); // (2) + + ThreadHelper::thread_sleep_tenth_sec(3); + + // the value after waiting 3 seconds + sal_Int32 nLaterValue = aCountThread->getValue(); // (3) + + resumeAndWaitThread(aCountThread); + termAndJoinThread(aCountThread); + delete aCountThread; + + CPPUNIT_ASSERT_MESSAGE( + "Suspend the thread", + bRes + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Suspend the thread", + nValue, nLaterValue + ); + + } + + CPPUNIT_TEST_SUITE(suspend); + CPPUNIT_TEST(suspend_001); + // LLA: Deadlocked!!! + // CPPUNIT_TEST(createSuspended_002); + CPPUNIT_TEST_SUITE_END(); + }; // class suspend + + /** Test of the osl::Thread::resume method + */ + class resume : public CppUnit::TestFixture + { + public: + /** check if the thread run samely as usual after suspend and resume + + ALGORITHM: + compare the values before and after suspend, they should be same, + then compare values before and after resume, the difference should be same as the sleep seconds number + */ + void resume_001() + { + OCountThread* pCountThread = new OCountThread(); + bool bRes = pCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + suspendCountThread(pCountThread); + + sal_Int32 nSuspendValue = pCountThread->getValue(); // (2) + // suspend for 3 seconds + ThreadHelper::thread_sleep_tenth_sec(3); + pCountThread->resume(); + + ThreadHelper::thread_sleep_tenth_sec(3); + sal_Int32 nResumeValue = pCountThread->getValue(); + + ThreadHelper::thread_sleep_tenth_sec(3); + sal_Int32 nLaterValue = pCountThread->getValue(); + + termAndJoinThread(pCountThread); + delete pCountThread; + + t_print("SuspendValue: %d\n", static_cast<int>(nSuspendValue)); + t_print("ResumeValue: %d\n", static_cast<int>(nResumeValue)); + t_print("LaterValue: %d\n", static_cast<int>(nLaterValue)); + + /* LLA: this assumption is no longer relevant: nResumeValue == nSuspendValue && */ + CPPUNIT_ASSERT_MESSAGE( + "Suspend then resume the thread", + nLaterValue >= 9 + ); + CPPUNIT_ASSERT_MESSAGE( + "Suspend then resume the thread", + nResumeValue > nSuspendValue + ); + CPPUNIT_ASSERT_MESSAGE( + "Suspend then resume the thread", + nLaterValue > nResumeValue + ); + + } + + /** Create a suspended thread then resume, check if the thread has run + */ + void resume_002() + { + myThread* newthread = new myThread; + bool bRes = newthread->createSuspended(); + CPPUNIT_ASSERT_MESSAGE ( "Can't create thread!", bRes ); + + newthread->resume(); + ThreadHelper::thread_sleep_tenth_sec(2); + sal_Int32 nValue = newthread->getValue(); + + termAndJoinThread(newthread); + delete newthread; + + t_print(" nValue = %d\n", static_cast<int>(nValue)); + + CPPUNIT_ASSERT_MESSAGE( + "Creates a suspended thread, then resume", + nValue >= 1 + ); + } + + CPPUNIT_TEST_SUITE(resume); + CPPUNIT_TEST(resume_001); + CPPUNIT_TEST(resume_002); + CPPUNIT_TEST_SUITE_END(); + }; // class resume + + /** Test of the osl::Thread::terminate method + */ + class terminate : public CppUnit::TestFixture + { + public: + /** Check after call terminate if the running thread running go on executing + + ALGORITHM: + before and after call terminate, the values should be the same + */ + void terminate_001() + { + OCountThread* aCountThread = new OCountThread(); + bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + ThreadHelper::thread_sleep_tenth_sec(2); + sal_Int32 nValue = aCountThread->getValue(); + aCountThread->terminate(); + ThreadHelper::thread_sleep_tenth_sec(2); + sal_Int32 nLaterValue = aCountThread->getValue(); + + // isRunning should be false after terminate + bool isRunning = aCountThread->isRunning(); + aCountThread->join(); + delete aCountThread; + + t_print(" nValue = %d\n", static_cast<int>(nValue)); + t_print("nLaterValue = %d\n", static_cast<int>(nLaterValue)); + + CPPUNIT_ASSERT_MESSAGE( + "Terminate the thread", + !isRunning + ); + CPPUNIT_ASSERT_MESSAGE( + "Terminate the thread", + nLaterValue >= nValue + ); + } + /** Check if a suspended thread will terminate after call terminate, different on w32 and on UNX + */ + void terminate_002() + { + OCountThread* aCountThread = new OCountThread(); + bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + ThreadHelper::thread_sleep_tenth_sec(1); + suspendCountThread(aCountThread); + sal_Int32 nValue = aCountThread->getValue(); + + // seems a suspended thread can not be terminated on W32, while on Solaris can + resumeAndWaitThread(aCountThread); + + ThreadHelper::thread_sleep_tenth_sec(2); + + termAndJoinThread(aCountThread); + sal_Int32 nLaterValue = aCountThread->getValue(); + delete aCountThread; + + t_print(" nValue = %d\n", static_cast<int>(nValue)); + t_print("nLaterValue = %d\n", static_cast<int>(nLaterValue)); + + CPPUNIT_ASSERT_MESSAGE( + "Suspend then resume the thread", + nLaterValue > nValue ); + } + + CPPUNIT_TEST_SUITE(terminate); + CPPUNIT_TEST(terminate_001); + CPPUNIT_TEST(terminate_002); + CPPUNIT_TEST_SUITE_END(); + }; // class terminate + + /** Test of the osl::Thread::join method + */ + class join : public CppUnit::TestFixture + { + public: + /** Check after call terminate if the thread running function will not go on executing + + the next statement after join will not exec before the thread terminates + ALGORITHM: + recode system time at the beginning of the thread run, call join, then record system time again, + the difference of the two times should be equal or more than 20 seconds, the CountThread normally terminates + */ + void join_001() + { + OCountThread *aCountThread = new OCountThread(); + bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + StopWatch aStopWatch; + aStopWatch.start(); + // TimeValue aTimeVal_befor; + // osl_getSystemTime( &aTimeVal_befor ); + //t_print("#join:the system time is %d,%d\n", pTimeVal_befor->Seconds,pTimeVal_befor->Nanosec); + + aCountThread->join(); + + //the below line will be executed after aCountThread terminate + // TimeValue aTimeVal_after; + // osl_getSystemTime( &aTimeVal_after ); + aStopWatch.stop(); + // sal_uInt32 nSec = aTimeVal_after.Seconds - aTimeVal_befor.Seconds; + double nSec = aStopWatch.getSeconds(); + t_print("join_001 nSec=%f\n", nSec); + delete aCountThread; + + CPPUNIT_ASSERT_MESSAGE( + "Join the thread: after the thread terminate", + nSec >= 2 + ); + + } + /** after terminated by another thread, join exited immediately + + ALGORITHM: + terminate the thread when value>=3, call join, check the beginning time and time after join, + the difference should be 3 seconds, join costs little time + */ + void join_002() + { + OCountThread *aCountThread = new OCountThread(); + bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + //record the time when the running begin + // TimeValue aTimeVal_befor; + // osl_getSystemTime( &aTimeVal_befor ); + StopWatch aStopWatch; + aStopWatch.start(); + + ThreadHelper::thread_sleep_tenth_sec(10); + termAndJoinThread(aCountThread); + + //the below line will be executed after aCountThread terminate + // TimeValue aTimeVal_after; + // osl_getSystemTime( &aTimeVal_after ); + // sal_uInt32 nSec = aTimeVal_after.Seconds - aTimeVal_befor.Seconds; + aStopWatch.stop(); + double nSec = aStopWatch.getSeconds(); + t_print("join_002 nSec=%f\n", nSec); + + delete aCountThread; + CPPUNIT_ASSERT_MESSAGE( + "Join the thread: after thread terminate by another thread", + nSec >= 1 + ); + } + + CPPUNIT_TEST_SUITE(join); + CPPUNIT_TEST(join_001); + CPPUNIT_TEST(join_002); + CPPUNIT_TEST_SUITE_END(); + }; // class join + + /** Test of the osl::Thread::isRunning method + */ + class isRunning : public CppUnit::TestFixture + { + public: + void isRunning_001() + { + OCountThread *aCountThread = new OCountThread(); + bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + bool bRun = aCountThread->isRunning(); + + ThreadHelper::thread_sleep_tenth_sec(2); + termAndJoinThread(aCountThread); + bool bTer = aCountThread->isRunning(); + delete aCountThread; + + CPPUNIT_ASSERT_MESSAGE( + "Test isRunning", + bRun + ); + CPPUNIT_ASSERT_MESSAGE( + "Test isRunning", + !bTer + ); + } + /** check the value of isRunning when suspending and after resume + */ + void isRunning_002() + { + OCountThread *aCountThread = new OCountThread(); + bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + // sal_Bool bRunning = aCountThread->isRunning(); + // sal_Int32 nValue = 0; + suspendCountThread(aCountThread); + + bool bRunning_sup = aCountThread->isRunning(); + ThreadHelper::thread_sleep_tenth_sec(2); + aCountThread->resume(); + ThreadHelper::thread_sleep_tenth_sec(2); + bool bRunning_res = aCountThread->isRunning(); + termAndJoinThread(aCountThread); + bool bRunning_ter = aCountThread->isRunning(); + delete aCountThread; + + CPPUNIT_ASSERT_MESSAGE( + "Test isRunning", + bRes ); + CPPUNIT_ASSERT_MESSAGE( + "Test isRunning", + bRunning_sup ); + CPPUNIT_ASSERT_MESSAGE( + "Test isRunning", + bRunning_res ); + CPPUNIT_ASSERT_MESSAGE( + "Test isRunning", + !bRunning_ter ); + + } + + CPPUNIT_TEST_SUITE(isRunning); + CPPUNIT_TEST(isRunning_001); + CPPUNIT_TEST(isRunning_002); + CPPUNIT_TEST_SUITE_END(); + }; // class isRunning + + /// check osl::Thread::setPriority + class setPriority : public CppUnit::TestFixture + { + public: + // insert your test code here. + OString getPrioName(oslThreadPriority _aPriority) + { + OString sPrioStr; + switch (_aPriority) + { + case osl_Thread_PriorityHighest: + sPrioStr = "Highest"_ostr; + break; + + case osl_Thread_PriorityAboveNormal: + sPrioStr = "AboveNormal"_ostr; + break; + + case osl_Thread_PriorityNormal: + sPrioStr = "Normal"_ostr; + break; + + case osl_Thread_PriorityBelowNormal: + sPrioStr = "BelowNormal"_ostr; + break; + + case osl_Thread_PriorityLowest: + sPrioStr = "Lowest"_ostr; + break; + default: + sPrioStr = "unknown"_ostr; + } + return sPrioStr; + } + + /** check 2 threads. + + ALGORITHM: + Here the function should show, that 2 different threads, + which only increase a value, should run at the same time with same prio. + The test fails, if the difference between the two values is more than 5% + but IMHO this isn't a failure, it's only a feature of the OS. + */ + + void check2Threads(oslThreadPriority _aPriority) + { + // initial 5 threads with different priorities + OAddThread* pThread = new OAddThread(); + OAddThread* p2Thread = new OAddThread(); + + //Create them and start running at the same time + pThread->create(); + pThread->setPriority(_aPriority); + p2Thread->create(); + p2Thread->setPriority(_aPriority); + + ThreadHelper::thread_sleep_tenth_sec(5); + + pThread->terminate(); + p2Thread->terminate(); + + sal_Int32 nValueNormal = pThread->getValue(); + + sal_Int32 nValueNormal2 = p2Thread->getValue(); + + OString sPrio = getPrioName(_aPriority); + t_print("After 10 tenth seconds\n"); + + t_print("nValue in %s Prio Thread is %d\n",sPrio.getStr(), static_cast<int>(nValueNormal)); + t_print("nValue in %s Prio Thread is %d\n", sPrio.getStr(), static_cast<int>(nValueNormal2)); + + // ThreadHelper::thread_sleep_tenth_sec(1); + pThread->join(); + p2Thread->join(); + + delete pThread; + delete p2Thread; + + sal_Int32 nDelta = abs(nValueNormal - nValueNormal2); + double nQuotient = std::max(nValueNormal, nValueNormal2); + CPPUNIT_ASSERT_MESSAGE( + "Quotient is zero, which means, there exist no right values.", + nQuotient != 0 + ); + double nDeltaPercent = nDelta / nQuotient * 100; + + t_print("Delta value %d, percent %f\n", static_cast<int>(nDelta), nDeltaPercent); + + // LLA: it's not a bug if the current OS is not able to handle thread scheduling right and good. + // like Windows XP + // LLA: CPPUNIT_ASSERT_MESSAGE( + // LLA: "Run 2 normal threads, the count diff more than 5 percent.", + // LLA: nDeltaPercent <= 5 + // LLA: ); + } + + void setPriority_001_1() + { + check2Threads(osl_Thread_PriorityHighest); + } + void setPriority_001_2() + { + check2Threads(osl_Thread_PriorityAboveNormal); + } + void setPriority_001_3() + { + check2Threads(osl_Thread_PriorityNormal); + } + void setPriority_001_4() + { + check2Threads(osl_Thread_PriorityBelowNormal); + } + void setPriority_001_5() + { + check2Threads(osl_Thread_PriorityLowest); + } + + void setPriority_002() + { + // initial 5 threads with different priorities + + OAddThread aHighestThread; + OAddThread aAboveNormalThread; + OAddThread aNormalThread; + //OAddThread *aBelowNormalThread = new OAddThread(); + //OAddThread *aLowestThread = new OAddThread(); + + //Create them and start running at the same time + aHighestThread.createSuspended(); + aHighestThread.setPriority(osl_Thread_PriorityHighest); + + aAboveNormalThread.createSuspended(); + aAboveNormalThread.setPriority(osl_Thread_PriorityAboveNormal); + + aNormalThread.createSuspended(); + aNormalThread.setPriority(osl_Thread_PriorityNormal); + /*aBelowNormalThread->create(); + aBelowNormalThread->setPriority(osl_Thread_PriorityBelowNormal); + aLowestThread->create(); + aLowestThread->setPriority(osl_Thread_PriorityLowest); + */ + + aHighestThread.resume(); + aAboveNormalThread.resume(); + aNormalThread.resume(); + + ThreadHelper::thread_sleep_tenth_sec(5); + + aHighestThread.suspend(); + aAboveNormalThread.suspend(); + aNormalThread.suspend(); + + termAndJoinThread(&aNormalThread); + termAndJoinThread(&aAboveNormalThread); + termAndJoinThread(&aHighestThread); + //aBelowNormalThread->terminate(); + //aLowestThread->terminate(); + + sal_Int32 nValueHighest = aHighestThread.getValue(); + + sal_Int32 nValueAboveNormal = aAboveNormalThread.getValue(); + + sal_Int32 nValueNormal = aNormalThread.getValue(); + + t_print("After 10 tenth seconds\n"); + t_print("nValue in Highest Prio Thread is %d\n", static_cast<int>(nValueHighest)); + t_print("nValue in AboveNormal Prio Thread is %d\n", static_cast<int>(nValueAboveNormal)); + t_print("nValue in Normal Prio Thread is %d\n", static_cast<int>(nValueNormal)); + +#ifndef _WIN32 + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueHighest > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueAboveNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueNormal > 0 + ); +#endif + } + + void setPriority_003() + { + // initial 5 threads with different priorities + OAddThread pHighestThread; + OAddThread pAboveNormalThread; + OAddThread pNormalThread; + OAddThread pBelowNormalThread; + OAddThread pLowestThread; + + //Create them and start running at the same time + pHighestThread.createSuspended(); + pHighestThread.setPriority(osl_Thread_PriorityHighest); + + pAboveNormalThread.createSuspended(); + pAboveNormalThread.setPriority(osl_Thread_PriorityAboveNormal); + + pNormalThread.createSuspended(); + pNormalThread.setPriority(osl_Thread_PriorityNormal); + + pBelowNormalThread.createSuspended(); + pBelowNormalThread.setPriority(osl_Thread_PriorityBelowNormal); + + pLowestThread.createSuspended(); + pLowestThread.setPriority(osl_Thread_PriorityLowest); + + pHighestThread.resume(); + pAboveNormalThread.resume(); + pNormalThread.resume(); + pBelowNormalThread.resume(); + pLowestThread.resume(); + + ThreadHelper::thread_sleep_tenth_sec(5); + + pHighestThread.suspend(); + pAboveNormalThread.suspend(); + pNormalThread.suspend(); + pBelowNormalThread.suspend(); + pLowestThread.suspend(); + + termAndJoinThread(&pHighestThread); + termAndJoinThread(&pAboveNormalThread); + termAndJoinThread(&pNormalThread); + termAndJoinThread(&pBelowNormalThread); + termAndJoinThread(&pLowestThread); + + sal_Int32 nValueHighest = pHighestThread.getValue(); + + sal_Int32 nValueAboveNormal = pAboveNormalThread.getValue(); + + sal_Int32 nValueNormal = pNormalThread.getValue(); + + sal_Int32 nValueBelowNormal = pBelowNormalThread.getValue(); + + sal_Int32 nValueLowest = pLowestThread.getValue(); + + t_print("After 10 tenth seconds\n"); + t_print("nValue in Highest Prio Thread is %d\n", static_cast<int>(nValueHighest)); + t_print("nValue in AboveNormal Prio Thread is %d\n", static_cast<int>(nValueAboveNormal)); + t_print("nValue in Normal Prio Thread is %d\n", static_cast<int>(nValueNormal)); + t_print("nValue in BelowNormal Prio Thread is %d\n", static_cast<int>(nValueBelowNormal)); + t_print("nValue in Lowest Prio Thread is %d\n", static_cast<int>(nValueLowest)); + +#ifndef _WIN32 + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueHighest > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueAboveNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueBelowNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueLowest > 0 + ); +#endif + } + + void setPriority_004() + { + // initial 5 threads with different priorities + // OAddThread *pHighestThread = new OAddThread(); + OAddThread pAboveNormalThread; + OAddThread pNormalThread; + OAddThread pBelowNormalThread; + OAddThread pLowestThread; + + //Create them and start running at the same time + // pHighestThread->createSuspended(); + // pHighestThread->setPriority(osl_Thread_PriorityHighest); + + pAboveNormalThread.createSuspended(); + pAboveNormalThread.setPriority(osl_Thread_PriorityAboveNormal); + + pNormalThread.createSuspended(); + pNormalThread.setPriority(osl_Thread_PriorityNormal); + + pBelowNormalThread.createSuspended(); + pBelowNormalThread.setPriority(osl_Thread_PriorityBelowNormal); + + pLowestThread.createSuspended(); + pLowestThread.setPriority(osl_Thread_PriorityLowest); + + // pHighestThread->resume(); + pAboveNormalThread.resume(); + pNormalThread.resume(); + pBelowNormalThread.resume(); + pLowestThread.resume(); + + ThreadHelper::thread_sleep_tenth_sec(5); + + // pHighestThread->suspend(); + pAboveNormalThread.suspend(); + pNormalThread.suspend(); + pBelowNormalThread.suspend(); + pLowestThread.suspend(); + + // termAndJoinThread(pHighestThread); + termAndJoinThread(&pAboveNormalThread); + termAndJoinThread(&pNormalThread); + termAndJoinThread(&pBelowNormalThread); + termAndJoinThread(&pLowestThread); + + // sal_Int32 nValueHighest = 0; + // nValueHighest = pHighestThread->getValue(); + + sal_Int32 nValueAboveNormal = pAboveNormalThread.getValue(); + + sal_Int32 nValueNormal = pNormalThread.getValue(); + + sal_Int32 nValueBelowNormal = pBelowNormalThread.getValue(); + + sal_Int32 nValueLowest = pLowestThread.getValue(); + + t_print("After 5 tenth seconds\n"); + t_print("nValue in AboveNormal Prio Thread is %d\n", static_cast<int>(nValueAboveNormal)); + t_print("nValue in Normal Prio Thread is %d\n", static_cast<int>(nValueNormal)); + t_print("nValue in BelowNormal Prio Thread is %d\n", static_cast<int>(nValueBelowNormal)); + t_print("nValue in Lowest Prio Thread is %d\n", static_cast<int>(nValueLowest)); + + // delete pHighestThread; + +#ifndef _WIN32 + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + /* nValueHighest > 0 && */ + nValueAboveNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueBelowNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueLowest > 0 + ); +#endif + } + void setPriority_005() + { + // initial 5 threads with different priorities + // OAddThread *pHighestThread = new OAddThread(); + // OAddThread *pAboveNormalThread = new OAddThread(); + OAddThread pNormalThread; + OAddThread pBelowNormalThread; + OAddThread pLowestThread; + + //Create them and start running at the same time + // pHighestThread->createSuspended(); + // pHighestThread->setPriority(osl_Thread_PriorityHighest); + + // pAboveNormalThread->createSuspended(); + // pAboveNormalThread->setPriority(osl_Thread_PriorityAboveNormal); + + pNormalThread.createSuspended(); + pNormalThread.setPriority(osl_Thread_PriorityNormal); + + pBelowNormalThread.createSuspended(); + pBelowNormalThread.setPriority(osl_Thread_PriorityBelowNormal); + + pLowestThread.createSuspended(); + pLowestThread.setPriority(osl_Thread_PriorityLowest); + + // pHighestThread->resume(); + // pAboveNormalThread->resume(); + pNormalThread.resume(); + pBelowNormalThread.resume(); + pLowestThread.resume(); + + ThreadHelper::thread_sleep_tenth_sec(5); + + // pHighestThread->suspend(); + // pAboveNormalThread->suspend(); + pNormalThread.suspend(); + pBelowNormalThread.suspend(); + pLowestThread.suspend(); + + // termAndJoinThread(pHighestThread); + // termAndJoinThread(pAboveNormalThread); + termAndJoinThread(&pNormalThread); + termAndJoinThread(&pBelowNormalThread); + termAndJoinThread(&pLowestThread); + + // sal_Int32 nValueHighest = 0; + // nValueHighest = pHighestThread->getValue(); + + // sal_Int32 nValueAboveNormal = 0; + // nValueAboveNormal = pAboveNormalThread->getValue(); + + sal_Int32 nValueNormal = pNormalThread.getValue(); + + sal_Int32 nValueBelowNormal = pBelowNormalThread.getValue(); + + sal_Int32 nValueLowest = pLowestThread.getValue(); + + t_print("After 5 tenth seconds\n"); + t_print("nValue in Normal Prio Thread is %d\n", static_cast<int>(nValueNormal)); + t_print("nValue in BelowNormal Prio Thread is %d\n", static_cast<int>(nValueBelowNormal)); + t_print("nValue in Lowest Prio Thread is %d\n", static_cast<int>(nValueLowest)); + +#ifndef _WIN32 + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + /* nValueHighest > 0 && */ + /* nValueAboveNormal > 0 && */ + nValueNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueBelowNormal > 0 + ); + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueLowest > 0 + ); +#endif + } + + CPPUNIT_TEST_SUITE(setPriority); +#ifndef __sun + CPPUNIT_TEST(setPriority_002); + CPPUNIT_TEST(setPriority_003); + CPPUNIT_TEST(setPriority_004); + CPPUNIT_TEST(setPriority_005); +#endif + CPPUNIT_TEST(setPriority_001_1); + CPPUNIT_TEST(setPriority_001_2); + CPPUNIT_TEST(setPriority_001_3); + CPPUNIT_TEST(setPriority_001_4); + CPPUNIT_TEST(setPriority_001_5); + CPPUNIT_TEST_SUITE_END(); + }; // class setPriority + + /** Test of the osl::Thread::getPriority method + */ + class getPriority : public CppUnit::TestFixture + { + public: + // insert your test code here. + void getPriority_001() + { + OAddThread *pHighestThread = new OAddThread(); + + //Create them and start running at the same time + pHighestThread->create(); + pHighestThread->setPriority(osl_Thread_PriorityHighest); + + oslThreadPriority aPriority = pHighestThread->getPriority(); + termAndJoinThread(pHighestThread); + delete pHighestThread; + + ThreadHelper::outputPriority(aPriority); + +// LLA: Priority settings may not work within some OS versions. +#if defined(_WIN32) || defined(__sun) + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "getPriority", + osl_Thread_PriorityHighest, aPriority + ); +#else +// LLA: Linux +// NO_PTHREAD_PRIORITY ??? + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "getPriority", + osl_Thread_PriorityNormal, aPriority + ); +#endif + } + + CPPUNIT_TEST_SUITE(getPriority); + CPPUNIT_TEST(getPriority_001); + CPPUNIT_TEST_SUITE_END(); + }; // class getPriority + + class getIdentifier : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + + void getIdentifier_001() + { + // insert your test code here. + } + + CPPUNIT_TEST_SUITE(getIdentifier); + CPPUNIT_TEST(getIdentifier_001); + CPPUNIT_TEST_SUITE_END(); + }; // class getIdentifier + + /** Test of the osl::Thread::getCurrentIdentifier method + */ + class getCurrentIdentifier : public CppUnit::TestFixture + { + public: + void getCurrentIdentifier_001() + { + oslThreadIdentifier oId; + OCountThread* pCountThread = new OCountThread; + pCountThread->create(); + pCountThread->setWait(3); + oId = Thread::getCurrentIdentifier(); + oslThreadIdentifier oIdChild = pCountThread->getIdentifier(); + termAndJoinThread(pCountThread); + delete pCountThread; + + CPPUNIT_ASSERT_MESSAGE( + "Get the identifier for the current active thread.", + oId != oIdChild); + } + + CPPUNIT_TEST_SUITE(getCurrentIdentifier); + CPPUNIT_TEST(getCurrentIdentifier_001); + CPPUNIT_TEST_SUITE_END(); + }; // class getCurrentIdentifier + + /** Test of the osl::Thread::wait method + */ + class waittest : public CppUnit::TestFixture + { + public: + /** call wait in the run method + + ALGORITHM: + tested thread wait nWaitSec seconds, main thread sleep (2) seconds, + then terminate the tested thread, due to the fact that the thread do a sleep(1) + wait(5) + it's finish after 6 seconds. + */ + void wait_001() + { + OCountThread *aCountThread = new OCountThread(); + sal_Int32 nWaitSec = 5; + aCountThread->setWait(nWaitSec); + // thread runs at least 5 seconds. + bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + //record the time when the running begin + StopWatch aStopWatch; + aStopWatch.start(); + + // wait a little bit, to let the thread the time, to start + ThreadHelper::thread_sleep_tenth_sec( 4 ); + + // if wait works, + // this function returns, after 4 sec. later + termAndJoinThread(aCountThread); + + // value should be one. + sal_Int32 nValue = aCountThread->getValue(); + + aStopWatch.stop(); + + // sal_uInt32 nSec = aTimeVal_after.Seconds - aTimeVal_befor.Seconds; + double nTenthSec = aStopWatch.getTenthSec(); + double nSec = aStopWatch.getSeconds(); + delete aCountThread; + t_print("nTenthSec = %f \n", nTenthSec); + t_print("nSec = %f \n", nSec); + t_print("nValue = %d \n", static_cast<int>(nValue)); + + CPPUNIT_ASSERT_MESSAGE( + "Wait: Blocks the calling thread for the given number of time.", + nTenthSec >= 5 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Wait: Blocks the calling thread for the given number of time.", + sal_Int32(1), nValue + ); + + } + + CPPUNIT_TEST_SUITE(waittest); + CPPUNIT_TEST(wait_001); + CPPUNIT_TEST_SUITE_END(); + }; // class waittest + + /** osl::Thread::yield method: can not design good test scenario to test up to now + */ + class yield : public CppUnit::TestFixture + { + public: + void yield_001() + { + // insert your test code here. + } + + CPPUNIT_TEST_SUITE(yield); + CPPUNIT_TEST(yield_001); + CPPUNIT_TEST_SUITE_END(); + }; // class yield + + /** Test of the osl::Thread::schedule method + */ + class schedule : public CppUnit::TestFixture + { + public: + + /** The requested thread will get terminate the next time schedule() is called. + + Note: on UNX, if call suspend thread is not the to be suspended thread, the to be + suspended thread will get suspended the next time schedule() is called, + while on w32, it's nothing with schedule. + + check if suspend and terminate work well via schedule + */ + void schedule_001() + { + OAddThread* aThread = new OAddThread(); + bool bRes = aThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + ThreadHelper::thread_sleep_tenth_sec(2); + aThread->suspend(); + ThreadHelper::thread_sleep_tenth_sec(1); + sal_Int32 nValue = aThread->getValue(); + ThreadHelper::thread_sleep_tenth_sec(3); + sal_Int32 nLaterValue = aThread->getValue(); + // resumeAndWaitThread(aThread); + t_print(" value = %d\n", static_cast<int>(nValue)); + t_print("later value = %d\n", static_cast<int>(nLaterValue)); + // if value and latervalue not equal, then the thread would not suspended + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Schedule: suspend works.", + nValue, nLaterValue + ); + + aThread->resume(); + ThreadHelper::thread_sleep_tenth_sec(2); + + aThread->terminate(); + sal_Int32 nValue_term = aThread->getValue(); + + aThread->join(); + sal_Int32 nValue_join = aThread->getValue(); + + t_print("value after term = %d\n", static_cast<int>(nValue_term)); + t_print("value after join = %d\n", static_cast<int>(nValue_join)); + + // nValue_term and nValue_join should be the same + // but should be differ from nValue + + delete aThread; + //check if thread really terminate after call terminate, if join immediately return + CPPUNIT_ASSERT_MESSAGE( + "Schedule: Returns False if the thread should terminate.", + nValue_join - nValue_term <= 1 + ); + CPPUNIT_ASSERT_MESSAGE( + "Schedule: Returns False if the thread should terminate.", + nValue_join - nValue_term >= 0 + ); + + } + + /** design a thread that has not call schedule in the workfunction--run method + */ + void schedule_002() + { + ONoScheduleThread aThread; // this thread runs 10 sec. (no schedule() used) + bool bRes = aThread.create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); + + ThreadHelper::thread_sleep_tenth_sec(2); + aThread.suspend(); + sal_Int32 nValue = aThread.getValue(); + + ThreadHelper::thread_sleep_tenth_sec(3); + sal_Int32 nLaterValue = aThread.getValue(); + ThreadHelper::thread_sleep_tenth_sec(5); + + resumeAndWaitThread(&aThread); + + t_print(" value = %d\n", static_cast<int>(nValue)); + t_print("later value = %d\n", static_cast<int>(nLaterValue)); + + //On windows, suspend works, so the values are same +#ifdef _WIN32 + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Schedule: don't schedule in thread run method, suspend works.", + nValue, nLaterValue + ); +#endif + + //On UNX, suspend does not work, so the difference of the values equals to sleep seconds number +#ifdef UNX + aThread.resume(); + CPPUNIT_ASSERT_MESSAGE( + "Schedule: don't schedule in thread run method, suspend does not work too.", + nLaterValue > nValue + ); +#endif + + // terminate will not work if no schedule in thread's work function + termAndJoinThread(&aThread); + sal_Int32 nValue_term = aThread.getValue(); + + t_print(" value term = %d\n", static_cast<int>(nValue_term)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Schedule: don't schedule in thread run method, terminate failed.", + static_cast<sal_Int32>(10), nValue_term + ); + } + + CPPUNIT_TEST_SUITE(schedule); + CPPUNIT_TEST(schedule_001); + CPPUNIT_TEST(schedule_002); + CPPUNIT_TEST_SUITE_END(); + }; // class schedule + + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::create, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::createSuspended, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::suspend, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::resume, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::terminate, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::join, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::isRunning, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::setPriority, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::getPriority, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::getIdentifier, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::getCurrentIdentifier, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::waittest, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::yield, "osl_Thread"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::schedule, "osl_Thread"); +} // namespace osl_Thread + +// destroy function when the binding thread terminate +static void destroyCallback(void * data) +{ + delete[] static_cast<char *>(data); +} + +static ThreadData myThreadData(destroyCallback); + +namespace { + +class myKeyThread : public Thread +{ +public: + // a public char member for test result checking + char m_Char_Test; + // for pass thread-special data to thread + explicit myKeyThread(const char cData) + : m_Char_Test(0) + { + m_nData = cData; + } +private: + char m_nData; + + void SAL_CALL run() override + { + char * pc = new char[2]; +// strcpy(pc, &m_nData); + memcpy(pc, &m_nData, 1); + pc[1] = '\0'; + + myThreadData.setData(pc); + char* pData = static_cast<char*>(myThreadData.getData()); + m_Char_Test = *pData; + // wait for long time to check the data value in main thread + ThreadHelper::thread_sleep_tenth_sec(3); + } +public: + virtual ~myKeyThread() override + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } +}; + +} + +static ThreadData idData; + +namespace { + +class idThread: public Thread +{ +public: + oslThreadIdentifier m_Id; +private: + void SAL_CALL run() override + { + std::unique_ptr<oslThreadIdentifier> pId( new oslThreadIdentifier ); + *pId = getIdentifier(); + idData.setData(pId.get()); + oslThreadIdentifier* pIdData = static_cast<oslThreadIdentifier*>(idData.getData()); + //t_print("Thread %d has Data %d\n", getIdentifier(), *pIdData); + m_Id = *pIdData; + } + +public: + virtual ~idThread() override + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } +}; + +} + +namespace osl_ThreadData +{ + + class ctors : public CppUnit::TestFixture + { + public: + + // insert your test code here. + void ctor_001() + { + + } + + CPPUNIT_TEST_SUITE(ctors); + CPPUNIT_TEST(ctor_001); + CPPUNIT_TEST_SUITE_END(); + }; // class ctors + + class setData : public CppUnit::TestFixture + { + public: + + /** the same instance of the class can have different values in different threads + */ + void setData_001() + { + idThread aThread1; + aThread1.create(); + idThread aThread2; + aThread2.create(); + + aThread1.join(); + aThread2.join(); + + oslThreadIdentifier aThreadId1 = aThread1.getIdentifier(); + oslThreadIdentifier aThreadId2 = aThread2.getIdentifier(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + aThread1.m_Id, aThreadId1 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + aThread2.m_Id, aThreadId2 + ); + + } + + void setData_002() + { + // at first, set the data a value + char* pc = new char[2]; + char nData = 'm'; + pc[0] = nData; + pc[1] = '\0'; + + myThreadData.setData(pc); + + myKeyThread aThread1('a'); + aThread1.create(); + myKeyThread aThread2('b'); + aThread2.create(); + // aThread1 and aThread2 should have not terminated yet, check current data, not 'a' 'b' + char* pChar = static_cast<char*>(myThreadData.getData()); + char aChar = *pChar; + + aThread1.join(); + aThread2.join(); + + // the saved thread data of aThread1 & aThread2, different + char cData1 = aThread1.m_Char_Test; + char cData2 = aThread2.m_Char_Test; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'a', cData1 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'b', cData2 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'm', aChar + ); + + } + /** setData the second time, and then getData + */ + void setData_003() + { + // at first, set the data a value + char* pc = new char[2]; + char nData = 'm'; + memcpy(pc, &nData, 1); + pc[1] = '\0'; + myThreadData.setData(pc); + + myKeyThread aThread1('a'); + aThread1.create(); + myKeyThread aThread2('b'); + aThread2.create(); + // aThread1 and aThread2 should have not terminated yet + // setData the second time + char* pc2 = new char[2]; + nData = 'o'; + memcpy(pc2, &nData, 1); + pc2[1] = '\0'; + + myThreadData.setData(pc2); + char* pChar = static_cast<char*>(myThreadData.getData()); + char aChar = *pChar; + + aThread1.join(); + aThread2.join(); + + // the saved thread data of aThread1 & aThread2, different + char cData1 = aThread1.m_Char_Test; + char cData2 = aThread2.m_Char_Test; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'a', cData1 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'b', cData2 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'o', aChar + ); + } + + CPPUNIT_TEST_SUITE(setData); + CPPUNIT_TEST(setData_001); + CPPUNIT_TEST(setData_002); + CPPUNIT_TEST(setData_003); + CPPUNIT_TEST_SUITE_END(); + }; // class setData + + class getData : public CppUnit::TestFixture + { + public: + + // After setData in child threads, get Data in the main thread, should be independent + void getData_001() + { + char* pc = new char[2]; + strcpy(pc, "i"); + myThreadData.setData(pc); + + myKeyThread aThread1('c'); + aThread1.create(); + myKeyThread aThread2('d'); + aThread2.create(); + + aThread1.join(); + aThread2.join(); + + char cData1 = aThread1.m_Char_Test; + char cData2 = aThread2.m_Char_Test; + + char* pChar = static_cast<char*>(myThreadData.getData()); + char aChar = *pChar; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'c', cData1 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'd', cData2 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'i', aChar + ); + } + + // setData then change the value in the address data pointer points, + // and then getData, should get the new value + void getData_002() + { + char* pc = new char[2]; + char nData = 'i'; + memcpy(pc, &nData, 1); + pc[1] = '\0'; + + myThreadData.setData(pc); + + myKeyThread aThread1('a'); + aThread1.create(); + myKeyThread aThread2('b'); + aThread2.create(); + + // change the value which pc points + char nData2 = 'j'; + memcpy(pc, &nData2, 1); + pc[1] = '\0'; + + void* pChar = myThreadData.getData(); + char aChar = *static_cast<char*>(pChar); + + aThread1.join(); + aThread2.join(); + + char cData1 = aThread1.m_Char_Test; + char cData2 = aThread2.m_Char_Test; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'a', cData1 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'b', cData2 + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ThreadData setData: ", + 'j', aChar + ); + + } + + CPPUNIT_TEST_SUITE(getData); + CPPUNIT_TEST(getData_001); + CPPUNIT_TEST(getData_002); + CPPUNIT_TEST_SUITE_END(); + }; // class getData + + CPPUNIT_TEST_SUITE_REGISTRATION(osl_ThreadData::ctors); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_ThreadData::setData); + CPPUNIT_TEST_SUITE_REGISTRATION(osl_ThreadData::getData); +} // namespace osl_ThreadData + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/process/osl_Thread.xsce b/sal/qa/osl/process/osl_Thread.xsce new file mode 100644 index 0000000000..11d0c5da12 --- /dev/null +++ b/sal/qa/osl/process/osl_Thread.xsce @@ -0,0 +1,18 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# +osl_Thread.setPriority.setPriority_001_1 unxsols4 diff --git a/sal/qa/osl/process/osl_process.cxx b/sal/qa/osl/process/osl_process.cxx new file mode 100644 index 0000000000..75a74a7176 --- /dev/null +++ b/sal/qa/osl/process/osl_process.cxx @@ -0,0 +1,436 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifdef IOS +#define CPPUNIT_PLUGIN_EXPORTED_NAME cppunitTest_osl_process +#endif + +#include <sal/types.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <osl/process.h> +#include <osl/file.hxx> +#include <osl/thread.h> +#include <rtl/ustring.hxx> + +#include <osl/module.hxx> +#include <sal/macros.h> + +#if defined HAVE_VALGRIND_HEADERS +#include <valgrind/valgrind.h> +#elif !defined _WIN32 +#define RUNNING_ON_VALGRIND false +#endif + +#include <iostream> +#include <vector> +#include <algorithm> +#include <string> + +#ifdef UNX +#if defined( MACOSX ) +# include <crt_externs.h> +# define environ (*_NSGetEnviron()) +# else + extern char** environ; +# endif +#endif + +using namespace osl; + +/** get binary Path. +*/ +static OUString getExecutablePath() +{ + OUString dirPath; + osl::Module::getUrlFromAddress( + reinterpret_cast<oslGenericFunction>(&getExecutablePath), dirPath); + dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') ); + dirPath = OUString::Concat(dirPath.subView( 0, dirPath.lastIndexOf('/') + 1)) + + "Executable"; + return dirPath; +} + +#if !defined _WIN32 + +namespace { + +class exclude +{ +public: + + explicit exclude(const std::vector<OString>& exclude_list) + { + for (auto& exclude_list_item : exclude_list) + exclude_list_.push_back(env_var_name(exclude_list_item)); + } + + bool operator() (const OString& env_var) const + { + return (exclude_list_.end() != + std::find( + exclude_list_.begin(), + exclude_list_.end(), + env_var_name(env_var))); + } + +private: + + // extract the name from an environment variable + // that is given in the form "NAME=VALUE" + static OString env_var_name(const OString& env_var) + { + sal_Int32 pos_equal_sign = + env_var.indexOf('='); + + if (pos_equal_sign != -1) + return env_var.copy(0, pos_equal_sign); + + return OString(); + } + +private: + std::vector<OString> exclude_list_; +}; + + void tidy_container(std::vector<OString> &env_container) + { + //sort them because there are no guarantees to ordering + std::sort(env_container.begin(), env_container.end()); + if (RUNNING_ON_VALGRIND) + { + std::erase_if( + env_container, + [](OString const & s) { + return s.startsWith("LD_PRELOAD=") + || s.startsWith("VALGRIND_LIB="); }); + } + } +} + + static void read_parent_environment(std::vector<OString>* env_container) + { + for (int i = 0; environ[i] != nullptr; i++) + env_container->push_back(OString(environ[i])); + tidy_container(*env_container); + } + +#endif + +class Test_osl_executeProcess : public CppUnit::TestFixture +{ + const OUString env_param_; + + OUString temp_file_url_; + OUString temp_file_path_; + rtl_uString* parameters_[2]; + static const int parameters_count_ = 2; + OUString suCWD; + OUString suExecutableFileURL; + +public: + + // ctor + Test_osl_executeProcess() : + env_param_(OUString("-env")), suCWD(getExecutablePath()) + { + parameters_[0] = env_param_.pData; + +#if defined(_WIN32) + suExecutableFileURL = suCWD + "/" "osl_process_child.exe"; +#else + suExecutableFileURL = suCWD + "/" "osl_process_child"; +#endif + } + + virtual void setUp() override + { + temp_file_path_ = create_temp_file(temp_file_url_); + parameters_[1] = temp_file_path_.pData; + } + + virtual void tearDown() override + { + osl::File::remove(temp_file_url_); + } + + OUString create_temp_file(OUString &temp_file_url) + { + FileBase::RC rc = FileBase::createTempFile(nullptr, nullptr, &temp_file_url); + CPPUNIT_ASSERT_EQUAL_MESSAGE("createTempFile failed", FileBase::E_None, rc); + + OUString temp_file_path; + rc = FileBase::getSystemPathFromFileURL(temp_file_url, temp_file_path); + CPPUNIT_ASSERT_EQUAL_MESSAGE("getSystemPathFromFileURL failed", FileBase::E_None, rc); + + return temp_file_path; + } + +#if !defined _WIN32 + + void read_child_environment(std::vector<OString>* env_container) + { + OString temp_file_name = OUStringToOString(OUString( + parameters_[1]), osl_getThreadTextEncoding()); + std::ifstream file(temp_file_name.getStr()); + + CPPUNIT_ASSERT_MESSAGE + ( + "I/O error, cannot open child environment file", + file.is_open() + ); + + std::string line; + line.reserve(1024); + while (std::getline(file, line, '\0')) + env_container->push_back(OString(line.c_str())); + tidy_container(*env_container); + } + + // environment of the child process that was + // started. The child process writes his + // environment into a file + void compare_environments() + { + std::vector<OString> parent_env; + read_parent_environment(&parent_env); + + std::vector<OString> child_env; + read_child_environment(&child_env); + + OString msg( + OString::number(parent_env.size()) + "/" + + OString::number(child_env.size())); + auto min = std::min(parent_env.size(), child_env.size()); + for (decltype(min) i = 0; i != min; ++i) { + CPPUNIT_ASSERT_EQUAL_MESSAGE( + msg.getStr(), parent_env[i], child_env[i]); + } + if (parent_env.size() != child_env.size()) { + CPPUNIT_ASSERT_EQUAL_MESSAGE( + (parent_env.size() >= child_env.size() + ? parent_env.back() : child_env.back()).getStr(), + parent_env.size(), child_env.size()); + } + } + + // compare the equal environment parts and the + // different part of the child environment + bool compare_merged_environments(const std::vector<OString>& different_env_vars) + { + std::vector<OString> parent_env; + read_parent_environment(&parent_env); + + for (auto& env : parent_env) + std::cout << "initially parent env: " << env << "\n"; + + //remove the environment variables that we have changed + //in the child environment from the read parent environment + std::erase_if(parent_env, exclude(different_env_vars)); + + for (auto& env : parent_env) + std::cout << "stripped parent env: " << env << "\n"; + + //read the child environment and exclude the variables that + //are different + std::vector<OString> child_env; + read_child_environment(&child_env); + + for (auto& env : child_env) + std::cout << "initial child env: " << env << "\n"; + //partition the child environment into the variables that + //are different to the parent environment (they come first) + //and the variables that should be equal between parent + //and child environment + auto iter_logical_end = + std::stable_partition(child_env.begin(), child_env.end(), exclude(different_env_vars)); + + std::vector<OString> different_child_env_vars(child_env.begin(), iter_logical_end); + child_env.erase(child_env.begin(), iter_logical_end); + + for (auto& env : child_env) + std::cout << "stripped child env: " << env << "\n"; + + bool common_env_size_equals = (parent_env.size() == child_env.size()); + bool common_env_content_equals = std::equal(child_env.begin(), child_env.end(), parent_env.begin()); + + for (auto& env_var : different_env_vars) + std::cout << "different should be: " << env_var << "\n"; + + for (auto& env_var : different_child_env_vars) + std::cout << "different are: " << env_var << "\n"; + + bool different_env_size_equals = (different_child_env_vars.size() == different_env_vars.size()); + bool different_env_content_equals = + std::equal(different_env_vars.begin(), different_env_vars.end(), different_child_env_vars.begin()); + + return (common_env_size_equals && common_env_content_equals && + different_env_size_equals && different_env_content_equals); + } + + // test that parent and child process have the + // same environment when osl_executeProcess will + // be called without setting new environment + // variables + void osl_execProc_parent_equals_child_environment() + { + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + suExecutableFileURL.pData, + parameters_, + parameters_count_, + osl_Process_NORMAL, + nullptr, + suCWD.pData, + nullptr, + 0, + &process); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_createProcess failed", + osl_Process_E_None, osl_error + ); + + osl_error = ::osl_joinProcess(process); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_joinProcess returned with failure", + osl_Process_E_None, osl_error + ); + + osl_freeProcessHandle(process); + + compare_environments(); + } + + #define ENV1 "PAT=a:\\" + #define ENV2 "PATHb=b:\\" + #define ENV3 "Patha=c:\\" + #define ENV4 "Patha=d:\\" + + void osl_execProc_merged_child_environment() + { + rtl_uString* child_env[4]; + OUString env1(ENV1); + OUString env2(ENV2); + OUString env3(ENV3); + OUString env4(ENV4); + + child_env[0] = env1.pData; + child_env[1] = env2.pData; + child_env[2] = env3.pData; + child_env[3] = env4.pData; + + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + suExecutableFileURL.pData, + parameters_, + parameters_count_, + osl_Process_NORMAL, + nullptr, + suCWD.pData, + child_env, + SAL_N_ELEMENTS(child_env), + &process); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_createProcess failed", + osl_Process_E_None, osl_error + ); + + osl_error = ::osl_joinProcess(process); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_joinProcess returned with failure", + osl_Process_E_None, osl_error + ); + + osl_freeProcessHandle(process); + + std::vector<OString> different_child_env_vars + { + ENV1 ""_ostr, + ENV2 ""_ostr, + ENV4 ""_ostr + }; + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_execProc_merged_child_environment", + compare_merged_environments(different_child_env_vars) + ); + } + +#endif + + void osl_execProc_test_batch() + { + oslProcess process; +#if defined(_WIN32) + OUString suBatch = suCWD + "/batch.bat"; +#else + OUString suBatch = suCWD + "/batch.sh"; +#endif + oslProcessError osl_error = osl_executeProcess( + suBatch.pData, + nullptr, + 0, + osl_Process_NORMAL, + nullptr, + suCWD.pData, + nullptr, + 0, + &process); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_createProcess failed", + osl_Process_E_None, osl_error + ); + + osl_error = ::osl_joinProcess(process); + + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "osl_joinProcess returned with failure", + osl_Process_E_None, osl_error + ); + + osl_freeProcessHandle(process); + } + + CPPUNIT_TEST_SUITE(Test_osl_executeProcess); + //TODO: Repair these (at least under Windows) +#if !defined(_WIN32) + CPPUNIT_TEST(osl_execProc_parent_equals_child_environment); + CPPUNIT_TEST(osl_execProc_merged_child_environment); +#endif + CPPUNIT_TEST(osl_execProc_test_batch); + ///TODO: Repair test (or tested function ;-) - test fails. + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(Test_osl_executeProcess); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/process/osl_process_child.cxx b/sal/qa/osl/process/osl_process_child.cxx new file mode 100644 index 0000000000..ee260956b2 --- /dev/null +++ b/sal/qa/osl/process/osl_process_child.cxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#if defined(_WIN32) // Windows +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#else +# include <unistd.h> +#endif + +#include <stdlib.h> +#include <fstream> +#include <string.h> + + +#ifdef UNX +#if defined( MACOSX ) +# include <crt_externs.h> +# define environ (*_NSGetEnviron()) +# else + extern char** environ; +# endif +#endif + +#ifdef _WIN32 +# define SLEEP(t) (Sleep((t)*1000)) +#else +# define SLEEP(t) (sleep((t))) +#endif + +static void wait_for_seconds(char* time) +{ + SLEEP(atoi(time)); +} + +#ifdef _WIN32 + +static void w_to_a(LPCWSTR strW, LPSTR strA, DWORD size) +{ + WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, size, nullptr, nullptr); +} + + static void dump_env(char* file_path) + { + LPWSTR env = GetEnvironmentStringsW(); + LPWSTR p = env; + + std::ofstream file(file_path); + + char buffer[32767]; + while (size_t l = wcslen(p)) + { + w_to_a(p, buffer, sizeof(buffer)); + file << buffer << '\0'; + p += l + 1; + } + FreeEnvironmentStringsW(env); + } +#else + static void dump_env(char* file_path) + { + std::ofstream file(file_path); + for (int i = 0; environ[i] != nullptr; ++i) + file << environ[i] << '\0'; + } +#endif + +int main(int argc, char* argv[]) +{ + if (argc > 2) + { + if (strcmp("-join", argv[1]) == 0) + { + // coverity[tainted_data] - this is a build-time only test tool + wait_for_seconds(argv[2]); + } + else if (strcmp("-env", argv[1]) == 0) + dump_env(argv[2]); + } + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/profile/osl_old_testprofile.cxx b/sal/qa/osl/profile/osl_old_testprofile.cxx new file mode 100644 index 0000000000..6d44ebde4c --- /dev/null +++ b/sal/qa/osl/profile/osl_old_testprofile.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <osl/profile.h> +#include <rtl/bootstrap.hxx> + +namespace osl_Profile +{ + class oldtests : public CppUnit::TestFixture + { + public: + void test_profile(); + + CPPUNIT_TEST_SUITE( oldtests ); + CPPUNIT_TEST( test_profile ); + CPPUNIT_TEST_SUITE_END( ); + }; + +void oldtests::test_profile() +{ + OUString baseUrl; + CPPUNIT_ASSERT(rtl::Bootstrap::get("UserInstallation", baseUrl)); + + // successful write + oslProfile hProfile = osl_openProfile( OUString(baseUrl + "/soffice.ini").pData, osl_Profile_WRITELOCK ); + CPPUNIT_ASSERT(hProfile != nullptr); + CPPUNIT_ASSERT_MESSAGE( + "cannot write into init file", + osl_writeProfileBool( hProfile, "testsection", "testbool", true )); + CPPUNIT_ASSERT(osl_closeProfile( hProfile )); + + // unsuccessful open + CPPUNIT_ASSERT_EQUAL(oslProfile(nullptr), osl_openProfile( OUString(baseUrl + "/not_existing_path/soffice.ini").pData, osl_Profile_WRITELOCK )); +} + +} // namespace osl_Profile + +CPPUNIT_TEST_SUITE_REGISTRATION( osl_Profile::oldtests ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/security/osl_Security.cxx b/sal/qa/osl/security/osl_Security.cxx new file mode 100644 index 0000000000..3c0764014b --- /dev/null +++ b/sal/qa/osl/security/osl_Security.cxx @@ -0,0 +1,622 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <sddl.h> +#undef min +#endif +#include "osl_Security_Const.h" +#include <osl/thread.h> +#include <rtl/process.h> +#include <sal/log.hxx> +#include <o3tl/char16_t2wchar_t.hxx> + +using namespace osl; +using namespace rtl; + +/** print a UNICODE String. +*/ +static void printUString( const OUString & str ) +{ + //t_print("#printUString_u# " ); + OString aString = OUStringToOString( str, RTL_TEXTENCODING_ASCII_US ); + t_print("%s\n", aString.getStr( ) ); +} + +// test code start here + +namespace osl_Security +{ + + /** testing the method: + Security() + */ + class ctors : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void ctors_001( ) + { + ::osl::Security aSec; + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: create a security its handle should not be NULL.", + aSec.getHandle( ) != nullptr ); + } + + CPPUNIT_TEST_SUITE( ctors ); + CPPUNIT_TEST( ctors_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class ctors + + /** testing the methods: + inline sal_Bool SAL_CALL logonUser(const OUString& strName, + const OUString& strPasswd); + inline sal_Bool SAL_CALL logonUser(const OUString & strName, + const OUString & strPasswd, + const OUString & strFileServer); + */ + class logonUser : public CppUnit::TestFixture + { + public: + bool bRes; + + void logonUser_user_pwd( ) + { + ::osl::Security aSec; + bRes = aSec.logonUser( aLogonUser, aLogonPasswd ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: check logon user through forwarded user name, pwd, passed in (UNX), failed in (W32).", + bRes ); + } + + void logonUser_user_pwd_server( ) + { + ::osl::Security aSec; + bRes = aSec.logonUser( aLogonUser, aLogonPasswd, aFileServer ); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: check logon user through forwarded user name, pwd and server name, failed in (UNX)(W32).", + bRes ); + } + + CPPUNIT_TEST_SUITE( logonUser ); + if ( !aStringForward.isEmpty() && aStringForward.indexOf( ' ' ) != -1 && ( aStringForward.indexOf( ' ' ) == aStringForward.lastIndexOf( ' ' ) ) ) + /// if user name and passwd are forwarded + { + CPPUNIT_TEST( logonUser_user_pwd ); + } + if ( !aStringForward.isEmpty() && aStringForward.indexOf( ' ' ) != -1 && ( aStringForward.indexOf( ' ' ) != aStringForward.lastIndexOf( ' ' ) ) ) + /// if user name and passwd and file server are forwarded + { + CPPUNIT_TEST( logonUser_user_pwd_server ); + } + CPPUNIT_TEST_SUITE_END( ); + }; // class logonUser + + /** testing the method: + inline sal_Bool Security::getUserIdent( OUString& strIdent) const + */ + class getUserIdent : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void getUserIdent_001( ) + { + ::osl::Security aSec; + OUString strID; + bRes = aSec.getUserIdent( strID ); + + OString aMessage = "strUserID: " + + OUStringToOString(strUserID, osl_getThreadTextEncoding()) + + ", strID: " + + OUStringToOString(strID, osl_getThreadTextEncoding()) + + ", bRes: " + + OString::boolean(bRes); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( aMessage.getStr(), strUserID, strID ); + CPPUNIT_ASSERT_MESSAGE( aMessage.getStr(), bRes ); + } + + CPPUNIT_TEST_SUITE( getUserIdent ); + CPPUNIT_TEST( getUserIdent_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class getUserIdent + + /** testing the method: + inline sal_Bool SAL_CALL getUserName( OUString& strName) const; + */ + class getUserName : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void getUserName_001( ) + { + ::osl::Security aSec; +#ifdef _WIN32 + OUString strName( strUserName ), strGetName; +#else + OUString strName( strUserName ), strGetName; +#endif + bRes = aSec.getUserName( strGetName ); + + sal_Int32 nPos = -1; + if (!strName.isEmpty()) + { + nPos = strGetName.indexOf(strName); + } + CPPUNIT_ASSERT_MESSAGE( "#test comment#: get UserName and compare it with names got at the beginning of the test.", + ( nPos >= 0 ) ); + CPPUNIT_ASSERT_MESSAGE( "#test comment#: get UserName and compare it with names got at the beginning of the test.", + bRes ); + } + + CPPUNIT_TEST_SUITE( getUserName ); + CPPUNIT_TEST( getUserName_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class getUserName + + /** testing the method: + inline sal_Bool Security::getConfigDir( OUString& strDirectory ) const + */ + class getConfigDir : public CppUnit::TestFixture + { + public: + bool bRes, bRes1; + + void getConfigDir_001( ) + { + ::osl::Security aSec; + OUString strConfig; + bRes = aSec.getConfigDir( strConfig ); + + CPPUNIT_ASSERT_MESSAGE( "failed to find a ConfigDir!", bRes ); + } + + CPPUNIT_TEST_SUITE( getConfigDir ); + CPPUNIT_TEST( getConfigDir_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class getConfigDir + + /** testing the method: + inline sal_Bool SAL_CALL isAdministrator() const; + */ + class isAdministrator : public CppUnit::TestFixture + { + public: + bool bRes; + + void isAdministrator_001( ) + { + ::osl::Security aSec; + bRes = aSec.isAdministrator( ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "#test comment#: check if the user is administrator at beginning, compare here.", + isAdmin, bRes ); + } + + CPPUNIT_TEST_SUITE( isAdministrator ); + CPPUNIT_TEST( isAdministrator_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class isAdministrator + + /** testing the method: + inline oslSecurity getHandle() const; + */ + class getHandle : public CppUnit::TestFixture + { + public: + bool bRes; + + void getHandle_001( ) + { + ::osl::Security aSec; + bRes = aSec.isAdministrator( ) == bool(osl_isAdministrator( aSec.getHandle( ) )); + + CPPUNIT_ASSERT_MESSAGE( "#test comment#: use getHandle function to call C API.", + bRes ); + } + + CPPUNIT_TEST_SUITE( getHandle ); + CPPUNIT_TEST( getHandle_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class getHandle + + class UserProfile : public CppUnit::TestFixture + { + public: + + void loadUserProfile( ) + { + ::osl::Security aSec; + bool bValue = osl_loadUserProfile(aSec.getHandle()); + + CPPUNIT_ASSERT_MESSAGE( "empty function.", !bValue ); + } + + void unloadUserProfile( ) + { + ::osl::Security aSec; + osl_unloadUserProfile(aSec.getHandle()); + CPPUNIT_ASSERT_MESSAGE( "empty function.", true ); + } + + CPPUNIT_TEST_SUITE( UserProfile ); + CPPUNIT_TEST( loadUserProfile ); + CPPUNIT_TEST( unloadUserProfile ); + CPPUNIT_TEST_SUITE_END( ); + }; // class UserProfile + + class loginUserOnFileServer : public CppUnit::TestFixture + { + public: + + void loginUserOnFileServer_001( ) + { + OUString suUserName; + OUString suPassword; + OUString suFileServer; + ::osl::Security aSec; + oslSecurity pSec = aSec.getHandle(); + + oslSecurityError erg = osl_loginUserOnFileServer(suUserName.pData, suPassword.pData, suFileServer.pData, &pSec); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "empty function.", osl_Security_E_UserUnknown, erg ); + } + + CPPUNIT_TEST_SUITE( loginUserOnFileServer ); + CPPUNIT_TEST( loginUserOnFileServer_001 ); + CPPUNIT_TEST_SUITE_END( ); + }; // class loginUserOnFileServer + +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::ctors); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::logonUser); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::getUserIdent); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::getUserName); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::getConfigDir); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::isAdministrator); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::getHandle); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::UserProfile); +CPPUNIT_TEST_SUITE_REGISTRATION(osl_Security::loginUserOnFileServer); + +} // namespace osl_Security + +/* This defines an own TestPlugIn implementation with an own initialize() + method that will be called after loading the PlugIn + */ +#include <cppunit/plugin/TestPlugInDefaultImpl.h> + +namespace { + +class MyTestPlugInImpl: public CPPUNIT_NS::TestPlugInDefaultImpl +{ + public: + MyTestPlugInImpl() {}; + void initialize( CPPUNIT_NS::TestFactoryRegistry *registry, + const CPPUNIT_NS::PlugInParameters ¶meters ) override; +}; + +} + +void MyTestPlugInImpl::initialize( CPPUNIT_NS::TestFactoryRegistry *, + const CPPUNIT_NS::PlugInParameters & ) +{ + /// start message + t_print("#Initializing ...\n" ); + t_print("#\n#logonUser function need root/Administrator account to test.\n" ); + t_print("#You can test by login with root/Administrator, and execute:\n" ); + t_print("#testshl2 -forward \"username password\" ../../../wntmsci9/bin/Security.dll\n" ); + t_print("# where username and password are forwarded account info.\n" ); + t_print("#if no text forwarded, this function will be skipped.\n" ); + + /// get system information +#if ( defined UNX ) + /// some initialization work for UNIX OS + + struct passwd* pw; + CPPUNIT_ASSERT_MESSAGE( "getpwuid: no password entry\n",( pw = getpwuid( getuid() ) ) != nullptr ); + + /// get user ID; + strUserID = OUString::number( getuid( ) ); + + /// get user Name; + strUserName = OUString::createFromAscii( pw->pw_name ); + + /// get home directory; + CPPUNIT_ASSERT_EQUAL_MESSAGE( "#Convert from system path to URL failed.", + ::osl::File::E_None, ::osl::File::getFileURLFromSystemPath( OUString::createFromAscii( pw->pw_dir ), strHomeDirectory ) ); + + /// get config directory; + strConfigDirectory = strHomeDirectory.copy(0); + + /// is administrator; + if( !getuid( ) ) + isAdmin = true; + +#endif +#if defined(_WIN32) + /// some initialization work for Windows OS + + /// Get the user name, computer name, user home directory. + LPWSTR lpszSystemInfo; // pointer to system information string + DWORD cchBuff = BUFSIZE; // size of computer or user name + WCHAR wchBuffer[BUFSIZE]; // buffer for string + + lpszSystemInfo = wchBuffer; + if( GetUserNameW(lpszSystemInfo, &cchBuff) ) + strUserName = o3tl::toU(lpszSystemInfo); + + cchBuff = BUFSIZE; + if( GetComputerNameW(lpszSystemInfo, &cchBuff) ) + strComputerName = o3tl::toU(lpszSystemInfo); + + /// Get user home directory. + HKEY hRegKey; + if (RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", &hRegKey) == ERROR_SUCCESS) + { + sal_Unicode PathW[_MAX_PATH]; + LSTATUS lRet; + DWORD lSize = sizeof(PathW); + DWORD Type; + + lRet = RegQueryValueExW(hRegKey, L"AppData", nullptr, &Type, reinterpret_cast<unsigned char *>(PathW), &lSize); + if ( ( lRet == ERROR_SUCCESS ) && ( Type == REG_SZ ) && ( _waccess( o3tl::toW(PathW), 0 ) == 0 ) ) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE( "#Convert from system path to URL failed.", + ::osl::File::E_None, ::osl::File::getFileURLFromSystemPath( OUString(PathW), strConfigDirectory ) ); + } + + lSize = sizeof(PathW); + lRet = RegQueryValueExW(hRegKey, L"Personal", nullptr, &Type, reinterpret_cast<unsigned char *>(PathW), &lSize); + if ( ( lRet == ERROR_SUCCESS ) && ( Type == REG_SZ ) && ( _waccess( o3tl::toW(PathW), 0 ) == 0 ) ) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE( "#Convert from system path to URL failed.", + ::osl::File::E_None, ::osl::File::getFileURLFromSystemPath( OUString(PathW), strHomeDirectory ) ); + } + + RegCloseKey(hRegKey); + } + + /// Get user Security ID: + + // Create buffers that may be large enough. If a buffer is too small, the count parameter will be set to the size needed. + const DWORD INITIAL_SIZE = 32; + DWORD cbSid = 0; + DWORD dwSidBufferSize = INITIAL_SIZE; + DWORD cchDomainName = 0; + DWORD dwDomainBufferSize = INITIAL_SIZE; + WCHAR * wszDomainName = nullptr; + SID_NAME_USE eSidType; + DWORD dwErrorCode = 0; + + OUString sLookupUserName = strUserName; + LPCWSTR wszAccName = o3tl::toW(sLookupUserName.getStr( )); + + // Create buffers for the SID and the domain name. + PSID pSid = static_cast<PSID>(new BYTE[dwSidBufferSize]); + memset( pSid, 0, dwSidBufferSize); + + wszDomainName = new WCHAR[dwDomainBufferSize]; + memset(wszDomainName, 0, dwDomainBufferSize*sizeof(WCHAR)); + + // Obtain the SID for the account name passed. + for ( ; ; ) + { + // Set the count variables to the buffer sizes and retrieve the SID. + cbSid = dwSidBufferSize; + cchDomainName = dwDomainBufferSize; + if (LookupAccountNameW( + nullptr, // Computer name. NULL for the local computer + wszAccName, + pSid, // Pointer to the SID buffer. Use NULL to get the size needed, + &cbSid, // Size of the SID buffer needed. + wszDomainName, // wszDomainName, + &cchDomainName, + &eSidType + )) + { + if (eSidType == SID_NAME_USE::SidTypeDomain) + { + // LookupAccountNameW returned SID of a domain; likely the hostname is the same as + // username (case-insensitive): something like "JOHNSMITH\JohnSmith", so looking up + // for "JohnSmith" without domain returns domain itself. Try getting the SID of the + // user using fully qualified name (the case of user of another domain having name + // identical this hostname is not handled). + sLookupUserName = OUString::Concat(o3tl::toU(wszDomainName)) + u"\\" + strUserName; + wszAccName = o3tl::toW(sLookupUserName.getStr()); + continue; + } + if (IsValidSid( pSid) == FALSE) + wprintf(L"# The SID for %s is invalid.\n", wszAccName); + break; + } + dwErrorCode = GetLastError(); + + // Check if one of the buffers was too small. + if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER) + { + if (cbSid > dwSidBufferSize) + { + // Reallocate memory for the SID buffer. + wprintf(L"# The SID buffer was too small. It will be reallocated.\n"); + delete[] static_cast<BYTE*>(pSid); + pSid = static_cast<PSID>(new BYTE[cbSid]); + memset( pSid, 0, cbSid); + dwSidBufferSize = cbSid; + } + if (cchDomainName > dwDomainBufferSize) + { + // Reallocate memory for the domain name buffer. + wprintf(L"# The domain name buffer was too small. It will be reallocated.\n"); + delete [] wszDomainName; + wszDomainName = new WCHAR[cchDomainName]; + memset(wszDomainName, 0, cchDomainName*sizeof(WCHAR)); + dwDomainBufferSize = cchDomainName; + } + } + else + { + wprintf(L"# LookupAccountNameW failed. GetLastError returned: %d\n", dwErrorCode); + break; + } + } + + LPWSTR pSidStr = nullptr; + if (ConvertSidToStringSidW(pSid, &pSidStr)) + { + strUserID = o3tl::toU(pSidStr); + LocalFree(pSidStr); + } + else + { + wprintf(L"# ConvertSidToStringSidW failed. GetLastError returned: %d\n", GetLastError()); + } + + delete [] static_cast<BYTE*>(pSid); + delete [] wszDomainName; + + /// check if logged in user is administrator: + + BOOL b; + SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY }; + PSID AdministratorsGroup; + b = AllocateAndInitializeSid( + &NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdministratorsGroup); + if(b) + { + if (!CheckTokenMembership( nullptr, AdministratorsGroup, &b)) + { + b = FALSE; + } + FreeSid(AdministratorsGroup); + } + + isAdmin = b; + +#endif + + /// print the information. + t_print("#\n#Retrieved system information is below:\n"); + + t_print("Computer Name: "); + if ( strComputerName.isEmpty()) + t_print("Not retrieved\n" ); + else + printUString( strComputerName ); + + t_print("Current User Name: "); + if ( strUserName.isEmpty()) + t_print("Not retrieved\n" ); + else + printUString( strUserName ); + + t_print("Current User Home Directory:"); + if ( strHomeDirectory.isEmpty()) + t_print("Not retrieved\n" ); + else + printUString( strHomeDirectory ); + + t_print("Current Config Directory: "); + if ( strConfigDirectory.isEmpty()) + t_print("Not retrieved\n" ); + else + printUString( strConfigDirectory ); + + t_print("Current UserID: "); + if ( strUserID.isEmpty()) + t_print("Not retrieved\n" ); + else + printUString( strUserID ); + + t_print("Current User is: "); + if ( !isAdmin ) + t_print("NOT Administrator.\n" ); + else + t_print("Administrator.\n" ); + + /// get and display forwarded text if available. + OUString args[ 3 ]; + int argsCount = 0; + sal_uInt32 n = rtl_getAppCommandArgCount(); + for (sal_uInt32 i = 0; i < n; ++i) + { + OUString arg; + rtl_getAppCommandArg(i, &arg.pData); + if( arg.startsWith("-") ) + continue; + if( argsCount >= 3 ) + { + SAL_WARN( "sal.osl", "Too many test arguments" ); + continue; + } + args[ argsCount++ ] = arg; + } + /// only forwarded two parameters, username and password. + if( argsCount == 2 ) + { + aLogonUser = args[ 0 ]; + t_print("\n#Forwarded username: "); + printUString( aLogonUser); + + aLogonPasswd = args[ 1 ]; + t_print("#Forwarded password: "); + for (int i = 0; i < aLogonPasswd.getLength(); ++i) + t_print("*"); + t_print("\n" ); + } + else if( argsCount == 3 ) + /// forwarded three parameters, username, password and fileserver. + { + aLogonUser = args[ 0 ]; + t_print("#Forwarded username: "); + printUString( aLogonUser); + + aLogonPasswd = args[ 1 ]; + t_print("#Forwarded password: "); + for (int i = 0; i < aLogonPasswd.getLength(); ++i) + t_print("*"); + t_print("\n" ); + + aFileServer = args[ 2 ]; + t_print("#Forwarded FileServer: "); + printUString( aFileServer ); + } + t_print("#\n#Initialization Done.\n" ); + +} + +/* Instantiate and register the own TestPlugIn and instantiate the default + main() function. + (This is done by CPPUNIT_PLUGIN_IMPLEMENT() for TestPlugInDefaultImpl) + */ + +CPPUNIT_PLUGIN_EXPORTED_FUNCTION_IMPL( MyTestPlugInImpl ); +CPPUNIT_PLUGIN_IMPLEMENT_MAIN(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/security/osl_Security_Const.h b/sal/qa/osl/security/osl_Security_Const.h new file mode 100644 index 0000000000..8329962a3d --- /dev/null +++ b/sal/qa/osl/security/osl_Security_Const.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SAL_QA_OSL_SECURITY_OSL_SECURITY_CONST_H +#define INCLUDED_SAL_QA_OSL_SECURITY_OSL_SECURITY_CONST_H + +#if defined(_WIN32) // Windows +#include <io.h> +#endif + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <osl/file.hxx> +#include <osl/security.hxx> + +#include <stdlib.h> +#include <stdio.h> + +#if (defined UNX) +#include <unistd.h> +#include <pwd.h> +#endif + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <cppunit/plugin/TestPlugInDefaultImpl.h> + +#define t_print printf + +#define BUFSIZE 1024 +const char pTestString[17] = "Sun Microsystems"; + +OUString aLogonUser, aLogonPasswd, aFileServer, aStringForward; +OUString strUserName, strComputerName, strHomeDirectory; +OUString strConfigDirectory, strUserID; + +bool isAdmin = false; + +#endif // INCLUDED_SAL_QA_OSL_SECURITY_OSL_SECURITY_CONST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/setthreadname/test-setthreadname.cxx b/sal/qa/osl/setthreadname/test-setthreadname.cxx new file mode 100644 index 0000000000..d33a0eddda --- /dev/null +++ b/sal/qa/osl/setthreadname/test-setthreadname.cxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cstdlib> +#include <iostream> +#include <limits> + +#include <sal/types.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <osl/thread.hxx> + +namespace { + +class TestThread: public osl::Thread { +private: + virtual void SAL_CALL run() override; +public: + TestThread() = default; + TestThread(const TestThread&) = delete; + TestThread& operator=(const TestThread&) = delete; +}; + +void TestThread::run() { +#if defined(_WIN32) + if (std::getenv("URE_TEST_SETTHREADNAME") != nullptr) { + // On Windows, setting thread names appears to only take effect when the + // process is being debugged, so attach a debugger now: + std::cout << "set: "; + std::cin.ignore(std::numeric_limits< int >::max(), '\n'); + } +#endif + setName("TestThread"); + if (std::getenv("URE_TEST_SETTHREADNAME") != nullptr) { + // On Linux, the thread name can now be observed with "ps -L"; on + // Windows, the thread name can now be observed in a debugger. + std::cout << "stop: "; + std::cin.ignore(std::numeric_limits< int >::max(), '\n'); + } +} + +class Test: public CppUnit::TestFixture { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + + void test(); +}; + +void Test::test() { + TestThread t; + t.create(); + t.join(); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/qa/osl/socket.cxx b/sal/qa/osl/socket.cxx new file mode 100644 index 0000000000..4598754a22 --- /dev/null +++ b/sal/qa/osl/socket.cxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <osl/socket.h> +#include <rtl/ustring.hxx> + +namespace +{ +class SocketTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(SocketTest); + CPPUNIT_TEST(test_createInetSocketAddr); + CPPUNIT_TEST(test_createInetBroadcastAddr); + CPPUNIT_TEST_SUITE_END(); + + void test_createInetSocketAddr() + { + OUString constexpr in(u"123.4.56.78"_ustr); + auto const addr = osl_createInetSocketAddr(in.pData, 100); + CPPUNIT_ASSERT(addr != nullptr); + CPPUNIT_ASSERT_EQUAL(osl_Socket_FamilyInet, osl_getFamilyOfSocketAddr(addr)); + OUString out; + auto const res = osl_getDottedInetAddrOfSocketAddr(addr, &out.pData); + CPPUNIT_ASSERT_EQUAL(osl_Socket_Ok, res); + CPPUNIT_ASSERT_EQUAL(in, out); + CPPUNIT_ASSERT_EQUAL(sal_Int32(100), osl_getInetPortOfSocketAddr(addr)); + osl_destroySocketAddr(addr); + } + + void test_createInetBroadcastAddr() + { + auto const addr = osl_createInetBroadcastAddr(u"123.4.56.78"_ustr.pData, 100); + CPPUNIT_ASSERT(addr != nullptr); + CPPUNIT_ASSERT_EQUAL(osl_Socket_FamilyInet, osl_getFamilyOfSocketAddr(addr)); + OUString out; + auto const res = osl_getDottedInetAddrOfSocketAddr(addr, &out.pData); + CPPUNIT_ASSERT_EQUAL(osl_Socket_Ok, res); + CPPUNIT_ASSERT_EQUAL(OUString("123.255.255.255"), out); + CPPUNIT_ASSERT_EQUAL(sal_Int32(100), osl_getInetPortOfSocketAddr(addr)); + osl_destroySocketAddr(addr); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SocketTest); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sal/qa/osl/thread/test_thread.cxx b/sal/qa/osl/thread/test_thread.cxx new file mode 100644 index 0000000000..12ddafc6d7 --- /dev/null +++ b/sal/qa/osl/thread/test_thread.cxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> +#include "osl/conditn.hxx" +#include "osl/thread.hxx" +#include "osl/time.h" +#include <chrono> + +namespace { + +osl::Condition global; + +class Thread: public osl::Thread { +public: + explicit Thread(osl::Condition & cond): m_cond(cond) {} + +private: + virtual void SAL_CALL run() {} + + virtual void SAL_CALL onTerminated() { + m_cond.set(); + CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok, global.wait()); + } + + osl::Condition & m_cond; +}; + +class Test: public CppUnit::TestFixture { +public: + // Nondeterministic, best effort test that an osl::Thread can be destroyed + // (and in particular osl_destroyThread---indirectly---be called) before the + // corresponding thread has terminated: + void test() { + for (int i = 0; i < 50; ++i) { + osl::Condition c; + Thread t(c); + CPPUNIT_ASSERT(t.create()); + // Make sure virtual Thread::run/onTerminated are called before + // Thread::~Thread: + CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok, c.wait()); + } + // Make sure Thread::~Thread is called before each spawned thread + // terminates: + global.set(); + // Give the spawned threads enough time to terminate: + osl::Thread::wait(std::chrono::seconds(20)); + } + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |