* Utils/Any added to the source 4.x-dev

Mon, 24 Mar 2014 22:23:22 +0200

author
cemkalyoncu
date
Mon, 24 Mar 2014 22:23:22 +0200
branch
4.x-dev
changeset 421
058a467651b3
parent 420
85e3fcfbc26c
child 422
5fc3781043fa

* Utils/Any added to the source
* Single byte charset for MSVC
* Fixed VS project generation
* Tests are performed on a special folder called Runtime
* Filesystem
- ApplicationDirectory for windows
- Windows delete function modified
- Windows better entry point handling
- Fixed windows directory enumeration
* More test cases

.hgignore file | annotate | diff | comparison | revisions
CMakeLists.txt file | annotate | diff | comparison | revisions
Scripts/Compiler.cmake file | annotate | diff | comparison | revisions
Scripts/Macros.cmake file | annotate | diff | comparison | revisions
Scripts/Testing.cmake file | annotate | diff | comparison | revisions
Source/Filesystem/Filesystem.cpp file | annotate | diff | comparison | revisions
Source/Filesystem/Linux.cpp file | annotate | diff | comparison | revisions
Source/Filesystem/Windows.cpp file | annotate | diff | comparison | revisions
Source/Utils/Any.h file | annotate | diff | comparison | revisions
Source/Utils/dir.cmake file | annotate | diff | comparison | revisions
Source/dir.cmake file | annotate | diff | comparison | revisions
Testing/Source/Unit/Filesystem.cpp file | annotate | diff | comparison | revisions
--- a/.hgignore	Fri Mar 21 20:37:55 2014 +0200
+++ b/.hgignore	Mon Mar 24 22:23:22 2014 +0200
@@ -3,6 +3,8 @@
 Lib
 Bin
 Docs/Latex
+Testing/Tests
+Testing/Runtime
 
 syntax: glob
 
--- a/CMakeLists.txt	Fri Mar 21 20:37:55 2014 +0200
+++ b/CMakeLists.txt	Mon Mar 24 22:23:22 2014 +0200
@@ -9,7 +9,11 @@
 SET(CMAKE_TESTING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/Testing)
 SET(CMAKE_DOCUMENT_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/Docs)
 
+OPTION(GORGON_FAST_ANY "Make any to work fast by removing empty checks. This will only apply to release mode." OFF)
 
+IF(GORGON_FAST_ANY)
+	SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DGORGON_FAST_ANY")
+ENDIF()
 
 INCLUDE(Scripts/Compiler.cmake)
 
--- a/Scripts/Compiler.cmake	Fri Mar 21 20:37:55 2014 +0200
+++ b/Scripts/Compiler.cmake	Mon Mar 24 22:23:22 2014 +0200
@@ -43,6 +43,7 @@
 
 #make sure 64bits cannot be activated
 IF(MSVC)
+	ADD_DEFINITIONS(-D_SBCS)
 	IF(${CMAKE_CL_64})
 		MESSAGE(FATAL_ERROR "Gorgon Library works only 32bits")
 	ENDIF()
--- a/Scripts/Macros.cmake	Fri Mar 21 20:37:55 2014 +0200
+++ b/Scripts/Macros.cmake	Mon Mar 24 22:23:22 2014 +0200
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
 
 MACRO(DoSource)
 	IF(${wd} MATCHES ".+")
@@ -10,7 +10,6 @@
 	STRING(REGEX REPLACE "/" "\\\\" srcgrp "${wd}")
 	STRING(REGEX REPLACE "Source" "" srcgrp "${srcgrp}")
 	STRING(REGEX REPLACE "^\\\\" "" srcgrp "${srcgrp}")
-	SOURCE_GROUP("${srcgrp}" FILES ${Local})
 	
 	IF(${wd} MATCHES ".+")
 		SET(LocalFixed)
@@ -31,6 +30,7 @@
 	ENDIF()
 
 	LIST(APPEND All ${LocalFixed})
+	SOURCE_GROUP("${srcgrp}" FILES ${LocalFixed})
 	
 	FOREACH(S ${Local})
 		IF(IS_DIRECTORY "${CMAKE_SOURCE_DIR}/${wd}/${S}")
--- a/Scripts/Testing.cmake	Fri Mar 21 20:37:55 2014 +0200
+++ b/Scripts/Testing.cmake	Mon Mar 24 22:23:22 2014 +0200
@@ -6,6 +6,7 @@
 
 ENABLE_TESTING()
 
+file(MAKE_DIRECTORY ${CMAKE_TESTING_DIRECTORY}/Runtime)
 
 FOREACH(file ${UnitTests})
 	SET(target "UnitTest-${file}")
@@ -20,7 +21,7 @@
 	SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_FLAGS "-I${CMAKE_TESTING_DIRECTORY}/Source -I${CMAKE_SOURCE_DIR}/Source")
 	TARGET_LINK_LIBRARIES(${target} Gorgon)
 	
-	ADD_TEST(${file} ${CMAKE_TESTING_DIRECTORY}/Tests/Unit/${target})
+	ADD_TEST(NAME ${file} WORKING_DIRECTORY ${CMAKE_TESTING_DIRECTORY}/Runtime COMMAND  ${CMAKE_TESTING_DIRECTORY}/Tests/Unit/${target})
 ENDFOREACH()
 
 
--- a/Source/Filesystem/Filesystem.cpp	Fri Mar 21 20:37:55 2014 +0200
+++ b/Source/Filesystem/Filesystem.cpp	Mon Mar 24 22:23:22 2014 +0200
@@ -16,51 +16,6 @@
 		return startupdir;
 	}
 	
-	std::string ApplicationDirectory() {
-		std::string path=Canonize("/proc/self/exe");
-		
-		return GetDirectory(path);
-	}
-	
-	bool Delete(const std::string &path) {
-		if(IsDirectory(path)) {
-			std::vector<std::string> open, dir;
-			open.push_back(path);
-			
-			// while we still have more to delete
-			while(open.size()) {
-				// get the path to delete
-				std::string path=open.back();
-				
-				// if the path is a directory and its
-				// contents are not considered
-				if(IsDirectory(path) && (!dir.size() || dir.back()!=path)) {
-					dir.push_back(path);
-
-					// list its contents into open list
-					Iterator it(path);
-					for(;it.IsValid(); it.Next()) {
-						if(*it!="." && *it!="..") {
-							open.push_back(path + "/" + *it);
-						}
-					}
-				}
-				else {
-					// if this is the directory to be erased
-					if(dir.back()==path) dir.pop_back();
-					open.pop_back();
-					
-					if(remove(path.c_str())!=0) return false;
-				}
-			}
-			
-			return true;
-		}
-		else {
-			return remove(path.c_str())==0;
-		}
-	}
-	
 	bool Copy(const std::vector<std::string> &source, const std::string &target) {
 		for(auto &s : source) {
 			if(!Copy(s, target)) return false;
--- a/Source/Filesystem/Linux.cpp	Fri Mar 21 20:37:55 2014 +0200
+++ b/Source/Filesystem/Linux.cpp	Mon Mar 24 22:23:22 2014 +0200
@@ -98,6 +98,45 @@
 		return ret;
 	}
 	
+	bool Delete(const std::string &path) {
+		if(IsDirectory(path)) {
+			std::vector<std::string> open, dir;
+			open.push_back(path);
+			
+			// while we still have more to delete
+			while(open.size()) {
+				// get the path to delete
+				std::string path=open.back();
+				
+				// if the path is a directory and its
+				// contents are not considered
+				if(IsDirectory(path) && (!dir.size() || dir.back()!=path)) {
+					dir.push_back(path);
+
+					// list its contents into open list
+					Iterator it(path);
+					for(;it.IsValid(); it.Next()) {
+						if(*it!="." && *it!="..") {
+							open.push_back(path + "/" + *it);
+						}
+					}
+				}
+				else {
+					// if this is the directory to be erased
+					if(dir.back()==path) dir.pop_back();
+					open.pop_back();
+					
+					if(remove(path.c_str())!=0) return false;
+				}
+			}
+			
+			return true;
+		}
+		else {
+			return remove(path.c_str())==0;
+		}
+	}
+	
 	bool ChangeDirectory(const std::string &path) {
 		return chdir(path.c_str())==0;
 	}
@@ -173,6 +212,12 @@
 		return rename(source.c_str(), target.c_str())==0;
 	}
 	
+	std::string ApplicationDirectory() {
+		std::string path=Canonize("/proc/self/exe");
+		
+		return GetDirectory(path);
+	}
+	
 	std::vector<EntryPoint> EntryPoints() {
 		std::vector<EntryPoint> entries;
 		
--- a/Source/Filesystem/Windows.cpp	Fri Mar 21 20:37:55 2014 +0200
+++ b/Source/Filesystem/Windows.cpp	Mon Mar 24 22:23:22 2014 +0200
@@ -84,6 +84,49 @@
 		return ret;
 	}
 
+	bool Delete(const std::string &path) {
+		if(IsDirectory(path)) {
+			std::vector<std::string> open, dir;
+			open.push_back(path);
+
+			// while we still have more to delete
+			while(open.size()) {
+				// get the path to delete
+				std::string path=open.back();
+
+				// if the path is a directory and its
+				// contents are not considered
+				if(IsDirectory(path) && (!dir.size() || dir.back()!=path)) {
+					dir.push_back(path);
+
+					// list its contents into open list
+					Iterator it(path);
+					for(;it.IsValid(); it.Next()) {
+						if(*it!="." && *it!="..") {
+							open.push_back(path + "/" + *it);
+						}
+					}
+				}
+				else {
+					// if this is the directory to be erased
+					if(dir.back()==path) {
+						dir.pop_back();
+						if(RemoveDirectory(path.c_str())==0) return false;
+					}
+					else {
+						if(remove(path.c_str())!=0) return false;
+					}
+					open.pop_back();
+				}
+			}
+
+			return true;
+		}
+		else {
+			return remove(path.c_str())==0;
+		}
+	}
+
 	bool ChangeDirectory(const std::string &path) {
 		return _chdir(path.c_str())==0;
 	}
@@ -118,6 +161,14 @@
 	bool Move(const std::string &source, const std::string &target) {
 		return MoveFile(source.c_str(), target.c_str())!=0;
 	}
+
+	std::string ApplicationDirectory() {
+		HMODULE hModule = GetModuleHandle(NULL);
+		char path[MAX_PATH];
+		GetModuleFileName(hModule, path, MAX_PATH);
+
+		return GetDirectory(path);
+	}
 	
 	std::vector<EntryPoint> EntryPoints() {
 		char drvs[512], name[128];
@@ -135,7 +186,7 @@
 		CHAR my_documents[MAX_PATH];
 		my_documents[0]=0;
 
-		SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, my_documents);
+		SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, my_documents);
 		
 		e.Path=my_documents;
 		e.Name="Home";
@@ -149,16 +200,15 @@
 			e.Path=drives;
 			if(e.Path.back()!='\\') e.Path.push_back('/');
 			fixwinslashes(e.Path);
+			name[0]=0;
 			if(GetVolumeInformation(drives, name, 128, &serial, NULL, &flags, NULL, 0)) {
 				e.Name=name;
+				if(e.Name.empty())
+					e.Name=e.Path;
 				e.Writable=!(flags&FILE_READ_ONLY_VOLUME);
 				e.Readable=true;
+				entries.push_back(e);
 			}
-			else {
-				e.Readable=false;
-				e.Writable=false;
-			}
-			entries.push_back(e);
 			drives+=std::strlen(drives)+1;
 		}
 
@@ -168,7 +218,7 @@
 	namespace internal {
 		class iterator_data {
 		public:
-			iterator_data() : data(nullptr) { }
+			iterator_data() : data(new WIN32_FIND_DATAA) { }
 			~iterator_data() {
 				FindClose(search_handle);
 				delete data;
@@ -195,6 +245,7 @@
 		}
 		
 		current=data->data->cFileName;
+		if(current=="." || current=="..") Next();
 	}
 	
 	Iterator::Iterator(const Iterator &other) {
--- a/Source/Utils/Any.h	Fri Mar 21 20:37:55 2014 +0200
+++ b/Source/Utils/Any.h	Mon Mar 24 22:23:22 2014 +0200
@@ -1,4 +1,4 @@
-///	This file contains class Any which is a container for any type and
+/// @file This file contains class Any which is a container for any type and
 ///	supports boxing, unboxing and copying; uses RTTI. Best be used with
 ///  built in types or POD structures
 /// @license
@@ -122,7 +122,7 @@
 
 		/// Creates a new Any from the given data. This constructor
 		/// moves the given data.
-		/// Requires type in the copied Any to be move constructible.
+		/// Requires type in the moved Any to be move constructible.
 		template <class T_>
 		explicit Any(T_ &&data) {
 			type=new Type<T_>;
@@ -217,7 +217,7 @@
 		/// Any. It can also be used to modify the value contained within
 		/// this Any.
 		/// @throw std::runtime_error if Any is empty
-		/// @throw std::bad_cast if types do not match
+		/// @throw std::bad_cast (debug only) if types do not match
 		template <class T_>
 		T_ &Get() {
 #ifndef GORGON_FAST_ANY
@@ -239,7 +239,7 @@
 		/// Any. It can also be used to modify the value contained within
 		/// this Any.
 		/// @throw std::runtime_error if Any is empty
-		/// @throw std::bad_cast if types do not match
+		/// @throw std::bad_cast (debug only) if types do not match
 		template <class T_>
 		const T_ &Get() const {
 #ifndef GORGON_FAST_ANY
@@ -259,6 +259,7 @@
 
 		/// Unsafe version of Get. Should be used as last resort. Only
 		/// const version is available.
+		/// @warning Does not perform type check even in debug mode
 		/// @throw std::runtime_error if Any is empty
 		template <class T_>
 		T_ UnsafeGet() const {
@@ -282,7 +283,7 @@
 		/// no cross type comparison will be performed. You may use 
 		/// `any.Get<originaltype>() == othertype_variable`
 		/// @throw std::runtime_error if Any is empty
-		/// @throw std::bad_cast if types do not match
+		/// @throw std::bad_cast (debug only) if types do not match
 		template <class T_>
 		bool operator ==(const T_ &content) const  {
 #ifndef GORGON_FAST_ANY
@@ -301,12 +302,12 @@
 
 		/// Compares two Any variables. 
 		/// @return true if both are empty or have their contents equal. 
-		/// @throw std::bad_cast if types do not match
+		/// @throw std::bad_cast (debug only) if types do not match
 		bool operator ==(const Any &content) const  {
-			if(!content && !this->content) {
+			if(!content.content && !this->content) {
 				return true;
 			}
-			else if(!content || !this->content) {
+			else if(!content.content || !this->content) {
 				return false;
 			}
 #ifdef _DEBUG
@@ -323,7 +324,7 @@
 		/// no cross type comparison will be performed. You may use 
 		/// `any.Get<originaltype>() == othertype_variable`
 		/// @throw std::runtime_error if Any is empty
-		/// @throw std::bad_cast if types do not match
+		/// @throw std::bad_cast (debug only) if types do not match
 		template <class T_>
 		bool operator !=(const T_ &content) const  {
 			return !operator==(content);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Utils/dir.cmake	Mon Mar 24 22:23:22 2014 +0200
@@ -0,0 +1,3 @@
+SET(Local
+  Any.h
+)
\ No newline at end of file
--- a/Source/dir.cmake	Fri Mar 21 20:37:55 2014 +0200
+++ b/Source/dir.cmake	Mon Mar 24 22:23:22 2014 +0200
@@ -1,4 +1,5 @@
 SET(Local
 	Filesystem
+	Utils
 	Threading.h
 )
--- a/Testing/Source/Unit/Filesystem.cpp	Fri Mar 21 20:37:55 2014 +0200
+++ b/Testing/Source/Unit/Filesystem.cpp	Mon Mar 24 22:23:22 2014 +0200
@@ -2,15 +2,112 @@
 
 #include <catch.h>
 
+#undef CreateDirectory
+
 #include <Filesystem.h>
 
 #include <iostream>
 #include <string>
 #include <stdlib.h>
+#include <cstring>
+
+namespace fs=Gorgon::Filesystem;
+
+
+TEST_CASE( "PathNotFoundError", "[PathNotFoundError]" ) {
+	try {
+		throw fs::PathNotFoundError("Not found text");
+	}
+	catch(const fs::PathNotFoundError &err) {
+		REQUIRE( std::strcmp(err.what(), "Not found text") == 0 ) ;
+	}
+
+	try {
+		throw fs::PathNotFoundError("Not found text");
+	}
+	catch(const std::runtime_error &err) {
+		REQUIRE( std::strcmp(err.what(), "Not found text") == 0 ) ;
+	}
+
+	try {
+		throw fs::PathNotFoundError("Not found text");
+	}
+	catch(const std::exception &err) {
+		REQUIRE( std::strcmp(err.what(), "Not found text") == 0 ) ;
+	}
+}
+
+
+
+TEST_CASE( "Create directory", "[CreateDirectory][IsDirectory][IsFile][Delete]" ) {
+	REQUIRE( fs::CreateDirectory("thisistest") );
+
+	REQUIRE( fs::IsDirectory("thisistest") );
+	REQUIRE_FALSE( fs::IsFile("thisistest") );
+
+	REQUIRE( fs::Delete("thisistest") );
+
+	REQUIRE_FALSE( fs::IsDirectory("thisistest") );
+	REQUIRE_FALSE( fs::IsFile("thisistest") );
+}
+
+TEST_CASE( "Create nested directory", "[CreateDirectory][IsDirectory][Delete]") {
+	REQUIRE( fs::CreateDirectory("this/is/test") );
+
+	REQUIRE( fs::IsDirectory("this/is/test") );
+
+	fs::Delete("this");
+
+	REQUIRE_FALSE( fs::IsDirectory("this/is/test") );
+	REQUIRE_FALSE( fs::IsDirectory("this/is") );
+	REQUIRE_FALSE( fs::IsDirectory("this") );
+}
+
+
+TEST_CASE( "Check file is not a directory", "[IsDirectory][Delete]") {
+	std::ofstream testfile("testfile.txt");
+	testfile.close();
+
+	REQUIRE_FALSE( fs::IsDirectory("testfile.txt") );
+
+	REQUIRE( fs::Delete("testfile.txt") );
+}
+
+
+TEST_CASE( "Check if a file is a file", "[IsFile]") {
+	std::ofstream testfile("testfile.txt");
+	testfile.close();
+
+	REQUIRE( fs::IsFile("testfile.txt") );
+
+	fs::Delete("testfile.txt");
+}
+
+
+TEST_CASE( "Check file exists", "[IsExists]") {
+	std::ofstream testfile("testfile.txt");
+	testfile.close();
+
+	REQUIRE( fs::IsExists("testfile.txt") );
+
+	fs::Delete("testfile.txt");
+
+	REQUIRE_FALSE( fs::IsExists("testfile.txt") );
+}
+
+TEST_CASE( "Check directory exists", "[IsExists]") {
+	fs::CreateDirectory("test");
+
+	REQUIRE( fs::IsExists("test") );
+
+	fs::Delete("test");
+
+	REQUIRE_FALSE( fs::IsExists("test") );
+}
 
 
 TEST_CASE( "Save - Saving file", "[Save]") {
-	Gorgon::Filesystem::Save("test.txt", "This is a test\n");
+	fs::Save("test.txt", "This is a test\n");
 	std::ifstream file("test.txt", std::ios::binary);
 	
 	REQUIRE( file.is_open() );
@@ -33,7 +130,7 @@
 	std::string teststring="This is a test\n";
 	teststring.push_back(0); //testing binary
 
-	Gorgon::Filesystem::Save("test.bin", teststring);
+	fs::Save("test.bin", teststring);
 	std::ifstream file("test.bin", std::ios::binary);
 	
 	file.seekg(0, std::ios::end);
@@ -48,10 +145,10 @@
 
 TEST_CASE( "Save - Overwrite", "[Save]") {
 	std::string teststring="This is a test\n";
-	Gorgon::Filesystem::Save("test.txt", teststring);
+	fs::Save("test.txt", teststring);
 	
 	teststring="t";
-	Gorgon::Filesystem::Save("test.txt", teststring);
+	fs::Save("test.txt", teststring);
 	
 	std::ifstream file("test.txt", std::ios::binary);
 	file.seekg(0, std::ios::end);
@@ -63,31 +160,31 @@
 
 
 
-TEST_CASE( "Load - Loading file", "[Load]") {	
+TEST_CASE( "Load - Loading file", "[Save][Load]") {	
 	std::string teststring="This is a test\n";
-	Gorgon::Filesystem::Save("test.txt", teststring);	
+	fs::Save("test.txt", teststring);	
 	
-	REQUIRE( Gorgon::Filesystem::Load("test.txt")==teststring );
+	REQUIRE( fs::Load("test.txt")==teststring );
 	
 	remove("test.txt");
 }
 
 
-TEST_CASE( "Load - Loading binary file", "[Load]") {	
+TEST_CASE( "Load - Loading binary file", "[Save][Load]") {	
 	std::string teststring="This is a test\n";
 	teststring.push_back(0);
-	Gorgon::Filesystem::Save("test.bin", teststring);	
+	fs::Save("test.bin", teststring);	
 	
-	REQUIRE( Gorgon::Filesystem::Load("test.bin")==teststring );
+	REQUIRE( fs::Load("test.bin")==teststring );
 	
 	remove("test.bin");
 }
 
 
-TEST_CASE( "Load - PathNotFoundError", "[Load]") {	
+TEST_CASE( "Load - PathNotFoundError", "[Load][PathNotFoundError") {	
 	REQUIRE_THROWS_AS( 
-		Gorgon::Filesystem::Load("thisfiledoesnotexists/iamsureofit.neverever"), 
-		Gorgon::Filesystem::PathNotFoundError 
+		fs::Load("thisfiledoesnotexists/iamsureofit.neverever"), 
+		fs::PathNotFoundError 
 	);
 }
 

mercurial