//
// FileTest.cpp
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#include "FileTest.h"
#include "CppUnit/TestCaller.h"
#include "CppUnit/TestSuite.h"
#include "Poco/File.h"
#include "Poco/TemporaryFile.h"
#include "Poco/Path.h"
#include "Poco/Exception.h"
#include "Poco/Thread.h"
#include "Poco/Environment.h"
#include <fstream>
#include <set>
#include <atomic>
#include <vector>
#include <thread>
#include <chrono>
#if defined(POCO_OS_FAMILY_UNIX)
#include <sys/stat.h>
#include <unistd.h>
#endif
#if defined(POCO_OS_FAMILY_WINDOWS)
#include <Windows.h>
#endif

using Poco::File;
using Poco::TemporaryFile;
using Poco::Path;
using Poco::Exception;
using Poco::Timestamp;
using Poco::Thread;


FileTest::FileTest(const std::string& name): CppUnit::TestCase(name)
{
}


FileTest::~FileTest()
{
}


void FileTest::testFileAttributes1()
{
	File f("testfile.dat");
	assertTrue (!f.exists());

	try
	{
		bool POCO_UNUSED flag = f.canRead();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		bool POCO_UNUSED flag = f.canWrite();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		bool POCO_UNUSED flag = f.isFile();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		bool POCO_UNUSED flag = f.isDirectory();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		Timestamp POCO_UNUSED ts = f.created();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		Timestamp POCO_UNUSED ts = f.getLastModified();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		Timestamp ts;
		f.setLastModified(ts);
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		File::FileSize POCO_UNUSED fs = f.getSize();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		f.setSize(0);
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		f.setWriteable();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		f.setReadOnly();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		f.copyTo("copy.dat");
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		f.moveTo("copy.dat");
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		f.renameTo("copy.dat");
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}

	try
	{
		f.remove();
		failmsg("file does not exist - must throw exception");
	}
	catch (Exception&)
	{
	}
}


void FileTest::testCreateFile()
{
	File f("testfile.dat");
	bool created = f.createFile();
	assertTrue (created);
	assertTrue (!f.isHidden());
	created = f.createFile();
	assertTrue (!created);
}


void FileTest::testExists()
{
	assertFalse (File("").exists());
	{
		File f("testfile.dat");
		f.createFile();
		assertTrue (f.exists());
		assertFalse (f.canExecute());
	}

	{
		File f("/testfile.dat");
		assertFalse (f.exists());
		assertFalse (f.canExecute());
	}

	{
#if defined(POCO_OS_FAMILY_UNIX)
		File f("echo");
		File f2("/dev/null");
#elif defined(POCO_OS_FAMILY_WINDOWS)
		std::string buffer(MAX_PATH, 0);
		UINT r = GetSystemDirectoryA(buffer.data(), static_cast<UINT>(buffer.size()));
		if (r)
		{
			Path p(buffer);
			p.makeDirectory().makeAbsolute().makeParent();
			buffer = p.toString();
			buffer.append("win.ini");
		}
		else
		{
			buffer = R"(c:\windows\win.ini)";
		}
		File f("cmd.exe");
		File f2(buffer);

		File f3("cmd");
		assertTrue (f3.canExecute());
		File f4("cmd-nonexistent");
		assertFalse (f4.canExecute());
#endif
		assertFalse (f.exists());
		assertFalse (f.getExecutablePath().empty());
		assertTrue (f.canExecute());

		assertTrue (f2.exists());
		assertFalse (f2.canExecute());
	}
}


void FileTest::testFileAttributes2()
{
	TemporaryFile f;
	bool created = f.createFile();
	Timestamp ts;
	assertTrue (created);

	assertTrue (f.exists());
	assertTrue (f.canRead());
	assertTrue (f.canWrite());
	assertTrue (f.isFile());
	assertTrue (!f.isDirectory());
	Timestamp tsc = f.created();
	Timestamp tsm = f.getLastModified();
	assertTrue (tsc - ts >= -2000000 && tsc - ts <= 2000000);
	assertTrue (tsm - ts >= -2000000 && tsm - ts <= 2000000);

	f.setWriteable(false);
	assertTrue (!f.canWrite());
	assertTrue (f.canRead());

	f.setReadOnly(false);
	assertTrue (f.canWrite());
	assertTrue (f.canRead());

	ts = Timestamp::fromEpochTime(1000000);
	f.setLastModified(ts);
	assertTrue (f.getLastModified() == ts);
}


void FileTest::testFileAttributes3()
{
#if defined(POCO_OS_FAMILY_UNIX)
#if POCO_OS==POCO_OS_CYGWIN
	File f("/dev/tty");
#else
	File f("/dev/null");
#endif
#elif defined(POCO_OS_FAMILY_WINDOWS)
	File f("CON");
#endif

	assertTrue (f.isDevice());
	assertTrue (!f.isFile());
	assertTrue (!f.isDirectory());
}


void FileTest::testCompare()
{
	File f1("abc.txt");
	File f2("def.txt");
	File f3("abc.txt");

	assertTrue (f1 == f3);
	assertTrue (!(f1 == f2));
	assertTrue (f1 != f2);
	assertTrue (!(f1 != f3));
	assertTrue (!(f1 == f2));
	assertTrue (f1 < f2);
	assertTrue (f1 <= f2);
	assertTrue (!(f2 < f1));
	assertTrue (!(f2 <= f1));
	assertTrue (f2 > f1);
	assertTrue (f2 >= f1);
	assertTrue (!(f1 > f2));
	assertTrue (!(f1 >= f2));

	assertTrue (f1 <= f3);
	assertTrue (f1 >= f3);
}


void FileTest::testRootDir()
{
#if defined(POCO_OS_FAMILY_WINDOWS)
	File f1("/");
	File f2("c:/");
	File f3("c:\\");
	File f4("\\");
	File f5("c:");
	File f6("\\\\?\\c:");
	File f7("\\\\?\\c:\\");

	assertTrue (f1.exists());
	assertTrue (f2.exists());
	assertTrue (f3.exists());
	assertTrue (f4.exists());
	assertTrue (f5.exists());
	assertTrue (f6.exists());
	assertTrue (f7.exists());
#else
	File f1("/");
	assertTrue (f1.exists());
#endif
}


void FileTest::testSwap()
{
	File f1("abc.txt");
	File f2("def.txt");
	f1.swap(f2);
	assertTrue (f1.path() == "def.txt");
	assertTrue (f2.path() == "abc.txt");
}


void FileTest::testSize()
{
	std::ofstream ostr("testfile.dat");
	ostr << "Hello, world!" << std::endl;
	ostr.close();
	File f("testfile.dat");
	assertTrue (f.getSize() > 0);
	f.setSize(0);
	assertTrue (f.getSize() == 0);
}


void FileTest::testDirectory()
{
	File d("testdir");
	try
	{
		d.remove(true);
	}
	catch (...)
	{
	}
	TemporaryFile::registerForDeletion("testdir");

	bool created = d.createDirectory();
	assertTrue (created);
	assertTrue (d.isDirectory());
	assertTrue (!d.isFile());
	std::vector<std::string> files;
	d.list(files);
	assertTrue (files.empty());

	File f = Path("testdir/file1", Path::PATH_UNIX);
	f.createFile();
	f = Path("testdir/file2", Path::PATH_UNIX);
	f.createFile();
	f = Path("testdir/file3", Path::PATH_UNIX);
	f.createFile();

	d.list(files);
	assertTrue (files.size() == 3);

	std::set<std::string> fs;
	fs.insert(files.begin(), files.end());
	assertTrue (fs.find("file1") != fs.end());
	assertTrue (fs.find("file2") != fs.end());
	assertTrue (fs.find("file3") != fs.end());

	File dd(Path("testdir/testdir2/testdir3", Path::PATH_UNIX));
	dd.createDirectories();
	assertTrue (dd.exists());
	assertTrue (dd.isDirectory());

	File ddd(Path("testdir/testdirB/testdirC/testdirD", Path::PATH_UNIX));
	ddd.createDirectories();
	assertTrue (ddd.exists());
	assertTrue (ddd.isDirectory());

	d.remove(true);
}


void FileTest::testCopy()
{
	std::ofstream ostr("testfile.dat");
	ostr << "Hello, world!" << std::endl;
	ostr.close();

	File f1("testfile.dat");
	TemporaryFile f2;
	f1.setReadOnly().copyTo(f2.path());
	assertTrue (f2.exists());
	assertTrue (!f2.canWrite());
	assertTrue (f1.getSize() == f2.getSize());
	f1.setWriteable().remove();
}


void FileTest::testCopyFailIfDestinationFileExists()
{
	std::ofstream ostr("testfile.dat");
	ostr << "Hello, world!" << std::endl;
	ostr.close();

	File f1("testfile.dat");
	TemporaryFile f2;
	f2.createFile();
	try {
		f1.setReadOnly().copyTo(f2.path(), File::OPT_FAIL_ON_OVERWRITE);
		failmsg("file exist - must throw exception");
	} catch (Exception&) {
	}
	f1.setWriteable().remove();
}


void FileTest::testMove()
{
	std::ofstream ostr("testfile.dat");
	ostr << "Hello, world!" << std::endl;
	ostr.close();

	File f1("testfile.dat");
	File::FileSize sz = f1.getSize();
	TemporaryFile f2;
	f1.moveTo(f2.path());
	assertTrue (f2.exists());
	assertTrue (f2.getSize() == sz);
	assertTrue (f1.exists());
	assertTrue (f1 == f2);
}


void FileTest::testMoveFailIfDestinationFileExists() {
	std::ofstream ostr("testfile.dat");
	ostr << "Hello, world!" << std::endl;
	ostr.close();

	File f1("testfile.dat");
	TemporaryFile f2;
	f2.createFile();
	try {
		f1.moveTo(f2.path(), File::OPT_FAIL_ON_OVERWRITE);
		failmsg("file exist - must throw exception");
	} catch (Exception&) {
	}
	f1.setWriteable().remove();
}


void FileTest::testCopyDirectory()
{
	Path pd1("testdir");
	File fd1(pd1);
	try
	{
		fd1.remove(true);
	}
	catch (...)
	{
	}
	fd1.createDirectories();
	Path pd2(pd1, "subdir");
	File fd2(pd2);
	fd2.createDirectories();
	Path pf1(pd1, "testfile1.dat");
	std::ofstream ostr1(pf1.toString().c_str());
	ostr1 << "Hello, world!" << std::endl;
	ostr1.close();
	Path pf2(pd1, "testfile2.dat");
	std::ofstream ostr2(pf2.toString().c_str());
	ostr2 << "Hello, world!" << std::endl;
	ostr2.close();
	Path pf3(pd2, "testfile3.dat");
	std::ofstream ostr3(pf3.toString().c_str());
	ostr3 << "Hello, world!" << std::endl;
	ostr3.close();

	File fd3("testdir2");

	try
	{
		fd3.remove(true);
	}
	catch (...)
	{
	}

	fd1.copyTo("testdir2");

	Path pd1t("testdir2");
	File fd1t(pd1t);
	assertTrue (fd1t.exists());
	assertTrue (fd1t.isDirectory());

	Path pd2t(pd1t, "subdir");
	File fd2t(pd2t);
	assertTrue (fd2t.exists());
	assertTrue (fd2t.isDirectory());

	Path pf1t(pd1t, "testfile1.dat");
	File ff1t(pf1t);
	assertTrue (ff1t.exists());
	assertTrue (ff1t.isFile());

	Path pf2t(pd1t, "testfile2.dat");
	File ff2t(pf2t);
	assertTrue (ff2t.exists());
	assertTrue (ff2t.isFile());

	Path pf3t(pd2t, "testfile3.dat");
	File ff3t(pf3t);
	assertTrue (ff3t.exists());
	assertTrue (ff3t.isFile());

	fd1.remove(true);
	fd3.remove(true);
}


void FileTest::testCopyDirectoryFailIfExists()
{
	Path pd1("testdir");
	File fd1(pd1);
	try {
		fd1.remove(true);
	} catch (...) {
	}
	fd1.createDirectories();
	Path pf1(pd1, "testfile1.dat");
	std::ofstream ostr1(pf1.toString().c_str());
	ostr1 << "Hello, world!" << std::endl;
	ostr1.close();
	Path pf2(pd1, "testfile2.dat");
	std::ofstream ostr2(pf2.toString().c_str());
	ostr2 << "Hello, world!" << std::endl;
	ostr2.close();

	Path pd2("destination");
	File fd2(pd2);
	try {
		fd2.remove(true);
	} catch (...) {
	}
	fd2.createDirectories();
	Path pd3(pd2, "testdir");
	File fd3(pd3);
	fd3.createDirectories();

	try {
		fd1.copyTo("testdir", File::OPT_FAIL_ON_OVERWRITE);
		failmsg("Destination Directory exists - must throw exception");
	} catch (Exception&) {
	}

	fd1.remove(true);
	fd2.remove(true);
}


void FileTest::testRename()
{
	std::ofstream ostr("testfile.dat");
	ostr << "Hello, world!" << std::endl;
	ostr.close();

	File f1("testfile.dat");
	File f2("testfile2.dat");
	f1.renameTo(f2.path());

	assertTrue (f2.exists());
	assertTrue (f1.exists());
	assertTrue (f1 == f2);

	f2.remove();
}


void FileTest::testRenameFailIfExists() {
	std::ofstream ostr("testfile.dat");
	ostr << "Hello, world!" << std::endl;
	ostr.close();

	File f1("testfile.dat");
	File f2("testfile2.dat");
	f2.createFile();

	try {
		f1.renameTo(f2.path(), File::OPT_FAIL_ON_OVERWRITE);
		failmsg("file exists - must throw exception");
	} catch (Exception&) {
	}

	f1.renameTo(f2.path());

	assertTrue(f2.exists());
	assertTrue(f1.exists());
	assertTrue(f1 == f2);

	f2.remove();
}


void FileTest::testLongPath()
{
#if defined(_WIN32)
	Poco::Path p("longpathtest");
	p.makeAbsolute();
	std::string longpath(p.toString());
	while (longpath.size() < MAX_PATH*4)
	{
		longpath.append("\\");
		longpath.append(64, 'x');
	}

	Poco::File d(longpath);
	d.createDirectories();

	assertTrue (d.exists());
	assertTrue (d.isDirectory());

	Poco::File f(p.toString());
	f.remove(true);
#endif
}

void FileTest::testUnixFileExtension()
{
	std::string filePath1 = "/a/b/c/.notextension";
	Poco::Path path1(filePath1, Poco::Path::Style::PATH_UNIX);

	assertEqual(".notextension", path1.getBaseName());
	assertEqual("", path1.getExtension());

	std::string filePath2 = "/a/b/c/emptyextension.";
	Poco::Path path2(filePath2, Poco::Path::Style::PATH_UNIX);

	assertEqual("emptyextension", path2.getBaseName());
	assertEqual("", path2.getExtension());
}


void FileTest::testTemporaryFile()
{
	const int COUNT = 10000;
	std::set<std::string> paths;
	for (int i = 0; i < COUNT; i++)
	{
		Poco::TemporaryFile f;
		paths.insert(f.path());
	}
	assertTrue (paths.size() == COUNT);
}


void FileTest::testGetExecutablePathNonExistent()
{
	// Non-existent bare command returns empty
	File f("myexecutable_nonexistent_xyz");
	assertTrue (f.getExecutablePath().empty());

	// Non-existent absolute path returns empty
#if defined(POCO_OS_FAMILY_WINDOWS)
	File f2(R"(C:\path\to\myexecutable_nonexistent)");
#else
	File f2("/usr/bin/myexecutable_nonexistent_xyz");
#endif
	assertTrue (f2.getExecutablePath().empty());
}


void FileTest::testGetExecutablePathResolve()
{
	// Real executable bare name resolves to absolute path
#if defined(POCO_OS_FAMILY_WINDOWS)
	File f("hostname");
	std::string execPath = f.getExecutablePath();
	if (!execPath.empty())
	{
		Path p(execPath);
		assertTrue (p.isAbsolute());
		assertTrue (File(execPath).canExecute());
	}
#else
	File f("ls");
	std::string execPath = f.getExecutablePath();
	assertFalse (execPath.empty());
	// Should be an absolute path (e.g. /bin/ls or /usr/bin/ls)
	assertTrue (execPath[0] == '/');
	assertTrue (f.canExecute());
#endif
}


void FileTest::testGetExecutablePathAbsolute()
{
#if defined(POCO_OS_FAMILY_UNIX)
	// Real executable absolute path resolves to itself
	std::string lsPath = File("ls").getExecutablePath();
	assertFalse (lsPath.empty());
	File f(lsPath);
	std::string execPath = f.getExecutablePath();
	assertEqual (lsPath, execPath);
#endif
}


void FileTest::testGetExecutablePathNonExecutable()
{
	// Non-executable file returns empty
#if defined(POCO_OS_FAMILY_UNIX)
	TemporaryFile tmp;
	tmp.createFile();
	chmod(tmp.path().c_str(), 0644);
	File f(tmp.path());
	assertTrue (f.getExecutablePath().empty());
#elif defined(POCO_OS_FAMILY_WINDOWS)
	// A temp file without PATHEXT extension is not executable
	TemporaryFile tmp;
	tmp.createFile();
	File f(tmp.path());
	assertTrue (f.getExecutablePath().empty());
#endif
}


void FileTest::testGetExecutablePathEmpty()
{
	File f("");
	assertTrue (f.getExecutablePath().empty());
}


void FileTest::testGetExecutablePathDirectory()
{
	// Directory returns empty (not a regular file)
	File f(Path::temp());
	assertTrue (f.getExecutablePath().empty());
}


void FileTest::testGetExecutablePathRelative()
{
#if defined(POCO_OS_FAMILY_UNIX)
	// Relative path with separator resolves to absolute
	std::string lsPath = File("ls").getExecutablePath();
	assertFalse (lsPath.empty());
	TemporaryFile tmpDir;
	tmpDir.createDirectories();
	std::string linkPath = tmpDir.path() + "/myls";
	symlink(lsPath.c_str(), linkPath.c_str());
	File f(linkPath);
	std::string execPath = f.getExecutablePath();
	assertFalse (execPath.empty());
	Path p(execPath);
	assertTrue (p.isAbsolute());
	assertTrue (File(execPath).canExecute());
#endif

	// Non-existent relative path with separator returns empty
#if defined(POCO_OS_FAMILY_UNIX)
	File f2("./nonexistent_xyz_12345");
	assertTrue (f2.getExecutablePath().empty());
#elif defined(POCO_OS_FAMILY_WINDOWS)
	File f2(R"(.\nonexistent_xyz_12345)");
	assertTrue (f2.getExecutablePath().empty());
#endif
}


void FileTest::testGetExecutablePathPATHEXT()
{
#if defined(POCO_OS_FAMILY_WINDOWS)
	// Command without extension resolves via PATHEXT
	File f("cmd");
	std::string execPath = f.getExecutablePath();
	if (!execPath.empty())
	{
		Path p(execPath);
		assertTrue (p.isAbsolute());
		assertTrue (File(execPath).canExecute());
	}
#endif
}


void FileTest::setUp()
{
	File f("testfile.dat");
	try
	{
		f.remove();
	}
	catch (...)
	{
	}
}


void FileTest::tearDown()
{
	File f("testfile.dat");
	try
	{
		f.remove();
	}
	catch (...)
	{
	}
}


#if defined(POCO_OS_FAMILY_UNIX)
void FileTest::testGetExecutablePathThreadSafety()
{
	// Test thread safety of PATH caching implementation (POSIX only)
	// Four threads: 2 calling getExecutablePath(), 2 modifying PATH

	std::vector<std::thread> threads;
	std::atomic<int> errorCount(0);
	std::atomic<bool> stopFlag(false);

	// Save original PATH
	std::string originalPath = Poco::Environment::get("PATH", "");

	auto execThreadFunc = [&errorCount, &stopFlag]()
	{
		try
		{
			for (int i = 0; i < 500 && !stopFlag.load(); ++i)
			{
				// Test executable lookup in PATH
				File f("ls");
				std::string path = f.getExecutablePath();
				if (path.empty())
				{
					errorCount++;
					break;
				}

				// Verify it's absolute
				if (path[0] != '/')
				{
					errorCount++;
					break;
				}

				// Verify canExecute consistency
				if (!f.canExecute())
				{
					errorCount++;
					break;
				}

				// Test another executable
				File f2("sh");
				std::string path2 = f2.getExecutablePath();
				if (!path2.empty() && !f2.canExecute())
				{
					errorCount++;
					break;
				}
			}
		}
		catch (...)
		{
			errorCount++;
		}
	};

	auto pathModifyThreadFunc = [&errorCount, &stopFlag, &originalPath]()
	{
		try
		{
			for (int i = 0; i < 200 && !stopFlag.load(); ++i)
			{
				// Modify PATH to trigger cache invalidation
				if (i % 2 == 0)
					Poco::Environment::set("PATH", originalPath + ":/tmp");
				else
					Poco::Environment::set("PATH", originalPath);

				// Small delay to let other threads run
				std::this_thread::sleep_for(std::chrono::milliseconds(1));
			}
		}
		catch (...)
		{
			errorCount++;
		}
	};

	// Launch 2 threads that call getExecutablePath()
	for (int i = 0; i < 2; ++i)
	{
		threads.emplace_back(execThreadFunc);
	}

	// Launch 2 threads that modify PATH
	for (int i = 0; i < 2; ++i)
	{
		threads.emplace_back(pathModifyThreadFunc);
	}

	// Wait for all threads to complete
	for (auto& t : threads)
	{
		t.join();
	}

	// Restore original PATH
	Poco::Environment::set("PATH", originalPath);

	// Verify no errors occurred
	assertEqual(0, errorCount.load());
}
#endif


CppUnit::Test* FileTest::suite()
{
	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FileTest");

	CppUnit_addTest(pSuite, FileTest, testCreateFile);
	CppUnit_addTest(pSuite, FileTest, testExists);
	CppUnit_addTest(pSuite, FileTest, testFileAttributes1);
	CppUnit_addTest(pSuite, FileTest, testFileAttributes2);
	CppUnit_addTest(pSuite, FileTest, testFileAttributes3);
	CppUnit_addTest(pSuite, FileTest, testCompare);
	CppUnit_addTest(pSuite, FileTest, testSwap);
	CppUnit_addTest(pSuite, FileTest, testSize);
	CppUnit_addTest(pSuite, FileTest, testDirectory);
	CppUnit_addTest(pSuite, FileTest, testCopy);
	CppUnit_addTest(pSuite, FileTest, testCopyFailIfDestinationFileExists);
	CppUnit_addTest(pSuite, FileTest, testMove);
	CppUnit_addTest(pSuite, FileTest, testMoveFailIfDestinationFileExists);
	CppUnit_addTest(pSuite, FileTest, testCopyDirectory);
	CppUnit_addTest(pSuite, FileTest, testCopyDirectoryFailIfExists);
	CppUnit_addTest(pSuite, FileTest, testRename);
	CppUnit_addTest(pSuite, FileTest, testRenameFailIfExists);
	CppUnit_addTest(pSuite, FileTest, testRootDir);
	CppUnit_addTest(pSuite, FileTest, testLongPath);
	CppUnit_addTest(pSuite, FileTest, testUnixFileExtension);
	CppUnit_addTest(pSuite, FileTest, testTemporaryFile);
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathNonExistent);
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathResolve);
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathAbsolute);
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathNonExecutable);
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathEmpty);
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathDirectory);
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathRelative);
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathPATHEXT);
#if defined(POCO_OS_FAMILY_UNIX)
	CppUnit_addTest(pSuite, FileTest, testGetExecutablePathThreadSafety);
#endif

	return pSuite;
}
