[Box Backup-commit] COMMIT r1331 - box/chris/general/test/common

boxbackup-dev@fluffy.co.uk boxbackup-dev@fluffy.co.uk
Sat, 03 Mar 2007 22:07:34 +0000


Author: chris
Date: 2007-03-03 22:07:34 +0000 (Sat, 03 Mar 2007)
New Revision: 1331

Modified:
   box/chris/general/test/common/testcommon.cpp
Log:
Added logging tests.

Fixed scope of objects that were interfering with memory leak test.

(from chris/merge)


Modified: box/chris/general/test/common/testcommon.cpp
===================================================================
--- box/chris/general/test/common/testcommon.cpp	2007-03-03 22:06:22 UTC (rev 1330)
+++ box/chris/general/test/common/testcommon.cpp	2007-03-03 22:07:34 UTC (rev 1331)
@@ -9,7 +9,9 @@
 
 #include "Box.h"
 
+#include <errno.h>
 #include <stdio.h>
+#include <time.h>
 
 #include "Test.h"
 #include "Configuration.h"
@@ -27,6 +29,8 @@
 #include "autogen_ConversionException.h"
 #include "CollectInBufferStream.h"
 #include "Archive.h"
+#include "Timer.h"
+#include "Logging.h"
 
 #include "MemLeakFindOn.h"
 
@@ -133,59 +137,117 @@
 	0
 };
 
+void safe_sleep(int seconds)
+{
+#ifdef WIN32
+	Sleep(seconds * 1000);
+#else
+	struct timespec ts;
+	ts.tv_sec  = seconds;
+	ts.tv_nsec = 0;
+	while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
+	{ /* sleep again */ }
+#endif
+}
+
+class TestLogger : public Logger
+{
+	private:
+	bool mTriggered;
+	Log::Level mTargetLevel;
+
+	public:
+	TestLogger(Log::Level targetLevel) 
+	: mTriggered(false), mTargetLevel(targetLevel)
+	{ 
+		Logging::Add(this);
+	}
+	~TestLogger() 
+	{
+		Logging::Remove(this);
+	}
+
+	bool IsTriggered() { return mTriggered; }
+	void Reset()       { mTriggered = false; }
+
+	virtual bool Log(Log::Level level, const std::string& rFile,
+		int line, std::string& rMessage)
+	{
+		if (level == mTargetLevel)
+		{
+			mTriggered = true;
+		}
+		return true;
+	}
+
+	virtual const char* GetType() { return "Test"; }
+	virtual void SetProgramName(const std::string& rProgramName) { }
+};
+
 int test(int argc, const char *argv[])
 {
 	// Test self-deleting temporary file streams
-	std::string tempfile("testfiles/tempfile");
-	TEST_CHECK_THROWS(InvisibleTempFileStream fs(tempfile.c_str()), 
-		CommonException, OSFileOpenError);
-	InvisibleTempFileStream fs(tempfile.c_str(), O_CREAT);
+	{
+		std::string tempfile("testfiles/tempfile");
+		TEST_CHECK_THROWS(InvisibleTempFileStream fs(tempfile.c_str()), 
+			CommonException, OSFileOpenError);
+		InvisibleTempFileStream fs(tempfile.c_str(), O_CREAT);
 
-#ifdef WIN32
-	// file is still visible under Windows
-	TEST_THAT(TestFileExists(tempfile.c_str()));
+	#ifdef WIN32
+		// file is still visible under Windows
+		TEST_THAT(TestFileExists(tempfile.c_str()));
 
-	// opening it again should work
-	InvisibleTempFileStream fs2(tempfile.c_str());
-	TEST_THAT(TestFileExists(tempfile.c_str()));
+		// opening it again should work
+		InvisibleTempFileStream fs2(tempfile.c_str());
+		TEST_THAT(TestFileExists(tempfile.c_str()));
 
-	// opening it to create should work
-	InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT);
-	TEST_THAT(TestFileExists(tempfile.c_str()));
+		// opening it to create should work
+		InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT);
+		TEST_THAT(TestFileExists(tempfile.c_str()));
 
-	// opening it to create exclusively should fail
-	TEST_CHECK_THROWS(InvisibleTempFileStream fs4(tempfile.c_str(), 
-		O_CREAT | O_EXCL), CommonException, OSFileOpenError);
+		// opening it to create exclusively should fail
+		TEST_CHECK_THROWS(InvisibleTempFileStream fs4(tempfile.c_str(), 
+			O_CREAT | O_EXCL), CommonException, OSFileOpenError);
 
-	fs2.Close();
-#else
-	// file is not visible under Unix
-	TEST_THAT(!TestFileExists(tempfile.c_str()));
+		fs2.Close();
+	#else
+		// file is not visible under Unix
+		TEST_THAT(!TestFileExists(tempfile.c_str()));
 
-	// opening it again should fail
-	TEST_CHECK_THROWS(InvisibleTempFileStream fs2(tempfile.c_str()),
-		CommonException, OSFileOpenError);
+		// opening it again should fail
+		TEST_CHECK_THROWS(InvisibleTempFileStream fs2(tempfile.c_str()),
+			CommonException, OSFileOpenError);
 
-	// opening it to create should work
-	InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT);
-	TEST_THAT(!TestFileExists(tempfile.c_str()));
+		// opening it to create should work
+		InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT);
+		TEST_THAT(!TestFileExists(tempfile.c_str()));
 
-	// opening it to create exclusively should work
-	InvisibleTempFileStream fs4(tempfile.c_str(), O_CREAT | O_EXCL);
-	TEST_THAT(!TestFileExists(tempfile.c_str()));
+		// opening it to create exclusively should work
+		InvisibleTempFileStream fs4(tempfile.c_str(), O_CREAT | O_EXCL);
+		TEST_THAT(!TestFileExists(tempfile.c_str()));
 
-	fs4.Close();
-#endif
+		fs4.Close();
+	#endif
 
-	fs.Close();
-	fs3.Close();
+		fs.Close();
+		fs3.Close();
 
-	// now that it's closed, it should be invisible on all platforms
-	TEST_THAT(!TestFileExists(tempfile.c_str()));
+		// now that it's closed, it should be invisible on all platforms
+		TEST_THAT(!TestFileExists(tempfile.c_str()));
+	}
 
-	// Test memory leak detection
+	// Test that memory leak detection doesn't crash
+	{
+		char *test = new char[1024];
+		delete [] test;
+		MemBlockStream *s = new MemBlockStream(test,12);
+		delete s;
+	}
+
 #ifdef BOX_MEMORY_LEAK_TESTING
 	{
+		Timers::Cleanup();
+
 		TEST_THAT(memleakfinder_numleaks() == 0);
 		void *block = ::malloc(12);
 		TEST_THAT(memleakfinder_numleaks() == 1);
@@ -201,10 +263,74 @@
 		TEST_THAT(memleakfinder_numleaks() == 1);
 		delete [] test;
 		TEST_THAT(memleakfinder_numleaks() == 0);
+
+		Timers::Init();
 	}
 #endif // BOX_MEMORY_LEAK_TESTING
+
+	// test main() initialises timers for us, so uninitialise them
+	Timers::Cleanup();
 	
+	// Check that using timer methods without initialisation
+	// throws an exception
+	TEST_CHECK_THROWS(Timers::Add(*(Timer*)NULL), 
+		CommonException, AssertFailed);
+	TEST_CHECK_THROWS(Timers::Remove(*(Timer*)NULL), 
+		CommonException, AssertFailed);
+	// TEST_CHECK_THROWS(Timers::Signal(), CommonException, AssertFailed);
+	TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, AssertFailed);
+	
+	// Check that we can initialise the timers
+	Timers::Init();
+	
+	// Check that double initialisation throws an exception
+	TEST_CHECK_THROWS(Timers::Init(), CommonException, AssertFailed);
 
+	// Check that we can clean up the timers
+	Timers::Cleanup();
+	
+	// Check that double cleanup throws an exception
+	TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, AssertFailed);
+
+	Timers::Init();
+
+	Timer t0(0); // should never expire
+	Timer t1(1);
+	Timer t2(2);
+	Timer t3(3);
+	
+	TEST_THAT(!t0.HasExpired());
+	TEST_THAT(!t1.HasExpired());
+	TEST_THAT(!t2.HasExpired());
+	TEST_THAT(!t3.HasExpired());
+	
+	safe_sleep(1);
+	TEST_THAT(!t0.HasExpired());
+	TEST_THAT(t1.HasExpired());
+	TEST_THAT(!t2.HasExpired());
+	TEST_THAT(!t3.HasExpired());
+	
+	safe_sleep(1);
+	TEST_THAT(!t0.HasExpired());
+	TEST_THAT(t1.HasExpired());
+	TEST_THAT(t2.HasExpired());
+	TEST_THAT(!t3.HasExpired());
+	
+	t1 = Timer(1);
+	t2 = Timer(2);
+	TEST_THAT(!t0.HasExpired());
+	TEST_THAT(!t1.HasExpired());
+	TEST_THAT(!t2.HasExpired());
+	
+	safe_sleep(1);
+	TEST_THAT(!t0.HasExpired());
+	TEST_THAT(t1.HasExpired());
+	TEST_THAT(!t2.HasExpired());
+	TEST_THAT(t3.HasExpired());
+
+	// Leave timers initialised for rest of test.
+	// Test main() will cleanup after test finishes.
+
 	static char *testfilelines[] =
 	{
 		"First line",
@@ -577,6 +703,8 @@
 	
 	// Test ExcludeList
 	{
+		TestLogger logger(Log::WARNING);
+
 		ExcludeList elist;
 		// Check assumption
 		TEST_THAT(Configuration::MultiValueSeparator == '\x01');
@@ -634,6 +762,24 @@
 		#endif
 
 		#undef CASE_SENSITIVE
+
+		TEST_THAT(!logger.IsTriggered());
+		elist.AddDefiniteEntries(std::string("/foo"));
+		TEST_THAT(!logger.IsTriggered());
+		elist.AddDefiniteEntries(std::string("/foo/"));
+		TEST_THAT(logger.IsTriggered());
+		logger.Reset();
+		elist.AddDefiniteEntries(std::string("/foo" 
+			DIRECTORY_SEPARATOR));
+		TEST_THAT(logger.IsTriggered());
+		logger.Reset();
+		elist.AddDefiniteEntries(std::string("/foo" 
+			DIRECTORY_SEPARATOR "bar\x01/foo"));
+		TEST_THAT(!logger.IsTriggered());
+		elist.AddDefiniteEntries(std::string("/foo" 
+			DIRECTORY_SEPARATOR "bar\x01/foo" 
+			DIRECTORY_SEPARATOR));
+		TEST_THAT(logger.IsTriggered());
 	}
 
 	test_conversions();