PageRenderTime 128ms CodeModel.GetById 61ms app.highlight 29ms RepoModel.GetById 31ms app.codeStats 0ms

/Utilities/Helpers/DirectoryHelper.cs

#
C# | 803 lines | 498 code | 91 blank | 214 comment | 39 complexity | 5b0d4aa036343df81646d165e75a79c3 MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.IO;
  4using System.Threading;
  5using NUnit.Framework;
  6
  7namespace Delta.Utilities.Helpers
  8{
  9	/// <summary>
 10	/// Directory helper
 11	/// </summary>
 12	public static class DirectoryHelper
 13	{
 14		#region Delegates
 15		internal delegate bool ExistsDelegate(string directory);
 16
 17		/// <summary>
 18		/// Delegate definition for getting the base directory. 
 19		/// </summary>
 20		/// <returns>String with the base directory</returns>
 21		internal delegate string GetBaseDirectoryDelegate();
 22
 23		/// <summary>
 24		/// Delegate definition for getting the current directory. 
 25		/// </summary>
 26		/// <returns>String with the current directory</returns>
 27		internal delegate string GetCurrentDirectoryDelegate();
 28
 29		/// <summary>
 30		/// Delegate definition for setting the current directory. 
 31		/// </summary>
 32		/// <param name="newDirectory">New Directory to switch into</param>
 33		internal delegate void SetCurrentDirectoryDelegate(string newDirectory);
 34
 35		/// <summary>
 36		/// Create a directory with the specific path.
 37		/// </summary>
 38		/// <param name="directoryPath">Directory path to create</param>
 39		internal delegate void CreateDirectoryDelegate(string directoryPath);
 40
 41		/// <summary>
 42		/// just Directory.GetFiles).
 43		/// </summary>
 44		/// <param name="path">File path for the search</param>
 45		/// <param name="searchPattern">Search Pattern</param>
 46		internal delegate string[] GetFilesDelegate(string path,
 47			string searchPattern);
 48
 49		internal delegate string[] GetDirectoriesDelegate(string path,
 50			string searchPattern);
 51
 52		internal delegate string[] GetDirectoriesRecursiveDelegate(string path,
 53			string searchPattern);
 54
 55		internal delegate void DeleteDelegate(string path);
 56		#endregion
 57
 58		#region Exists (Static)
 59		/// <summary>
 60		/// Helper method to figure out if a directory exists, will just call
 61		/// MethodAccessException, there we use the isolated storage instead.
 62		/// </summary>
 63		/// <param name="directory">
 64		/// Directory to check for. If this is null or empty, true is returned (the
 65		/// current path we are in obviously exists).
 66		/// </param>
 67		/// <returns>True if the directory path exists, false otherwise</returns>
 68		public static bool Exists(string directory)
 69		{
 70			if (String.IsNullOrEmpty(directory))
 71			{
 72				return true;
 73			}
 74
 75			return ExistsCallback(directory);
 76		}
 77		#endregion
 78
 79		#region GetBaseDirectory (Static)
 80		/// <summary>
 81		/// Get base directory where the application was started, is usually the
 82		/// same as GetCurrentDirectory, but can differ if current directory was
 83		/// changed (e.g. via SetCurrentDirectory).
 84		/// </summary>
 85		/// <returns>String with the base directory</returns>
 86		public static string GetBaseDirectory()
 87		{
 88			return GetBaseDirectoryCallback();
 89		}
 90		#endregion
 91
 92		#region GetCurrentDirectory (Static)
 93		/// <summary>
 94		/// Get current directory, just uses Directory.GetCurrentDirectory except
 95		/// </summary>
 96		/// <returns>String with the current directory</returns>
 97		public static string GetCurrentDirectory()
 98		{
 99			return GetCurrentDirectoryCallback();
100		}
101		#endregion
102
103		#region SetCurrentDirectory (Static)
104		/// <summary>
105		/// Set current directory, just uses Directory.SetCurrentDirectory except
106		/// </summary>
107		/// <param name="newDirectory">New Directory to switch into</param>
108		public static void SetCurrentDirectory(string newDirectory)
109		{
110			SetCurrentDirectoryCallback(newDirectory);
111		}
112		#endregion
113
114		#region CreateDirectory (Static)
115		/// <summary>
116		/// Create a directory with the specific path.
117		/// </summary>
118		/// <param name="directoryPath">Directory path to create</param>
119		/// <param name="deleteIfExists">
120		/// If the directory already exists, then delete it or not.
121		/// </param>
122		public static void CreateDirectory(string directoryPath,
123			bool deleteIfExists = false)
124		{
125			bool existsAlready = Exists(directoryPath);
126			if (deleteIfExists &&
127			    existsAlready)
128			{
129				Delete(directoryPath, true);
130				// Wait a bit to not confuse the OS with the creation of the directory
131				// we just deleted! If we don't do this the creation below might fail.
132				Thread.Sleep(10);
133			}
134
135			// We cannot create the current relative directory (empty string)
136			// And we only need to create if the directory does not exist yet.
137			if (String.IsNullOrEmpty(directoryPath) == false &&
138				(deleteIfExists ||
139				existsAlready == false))
140			{
141				CreateDirectoryCallback(directoryPath);
142			}
143		}
144		#endregion
145
146		#region GetFiles (Static)
147		/// <summary>
148		/// Get files helper method.
149		/// </summary>
150		/// <param name="path">File path for the search</param>
151		/// <param name="searchPattern">Search Pattern</param>
152		/// <returns>
153		/// Files in the directory matching searchPattern as filename string list
154		/// with full file paths.
155		/// </returns>
156		public static string[] GetFiles(string path, string searchPattern)
157		{
158			// If path does not exist, Directory.GetFiles would throw an exception
159			if (String.IsNullOrEmpty(path) ||
160			    Exists(path) == false)
161			{
162				return new string[0];
163			}
164			return GetFilesCallback(path, searchPattern);
165		}
166		#endregion
167
168		#region GetFilesRecursive (Static)
169		/// <summary>
170		/// Get files function with recursive file searching in sub directories.
171		/// </summary>
172		/// <param name="path">File path for the start of the search</param>
173		/// <param name="searchPattern">Search Pattern</param>
174		/// <returns>
175		/// Files in the directory and any sub directory matching searchPattern as
176		/// filename string list (with full absolute file paths).
177		/// </returns>
178		public static string[] GetFilesRecursive(string path,
179			string searchPattern)
180		{
181			// check null or empty and path exists
182			if (String.IsNullOrEmpty(path) ||
183			    Exists(path) == false)
184			{
185				return new string[0];
186			}
187
188			List<string> files = new List<string>();
189
190			try
191			{
192				// find all directories in the current
193				foreach (string s in GetDirectories(path))
194				{
195					// add the search results of the next folder
196					files.AddRange(GetFilesRecursive(s, searchPattern));
197				}
198
199				// add the files of the current directory
200				files.AddRange(GetFiles(path, searchPattern));
201			}
202			catch (Exception ex)
203			{
204				Log.Warning("GetFiles failed for the following reason:" + ex);
205			}
206
207			// return the collected files list
208			return files.ToArray();
209		}
210		#endregion
211
212		#region GetFilesMultiPattern (Static)
213		/// <summary>
214		/// Same as normal GetFiles but with the option to use multi patterns,
215		/// e.g. "*.txt|*.wma".
216		/// </summary>
217		/// <param name="path">Path to search for files in.</param>
218		/// <param name="searchPattern">Multiple pattern separated by an |</param>
219		/// <param name="recursive">Recursive file search</param>
220		/// <returns>Array of found files.</returns>
221		public static string[] GetFilesMultiPattern(string path,
222			string searchPattern, bool recursive = false)
223		{
224			string[] patterns = searchPattern.Split('|');
225			List<string> foundFiles = new List<string>();
226			foreach (string pattern in patterns)
227			{
228				if (recursive)
229				{
230					foundFiles.AddRange(GetFilesRecursive(path, pattern));
231				}
232				else
233				{
234					foundFiles.AddRange(GetFiles(path, pattern));
235				}
236			}
237
238			return foundFiles.ToArray();
239		}
240		#endregion
241
242		#region GetDirectories (Static)
243		/// <summary>
244		/// Get the directories in the given path.
245		/// </summary>
246		/// <param name="path">Path</param>
247		/// <returns>Array of sub directories of path</returns>
248		public static string[] GetDirectories(string path)
249		{
250			return GetDirectories(path, "*");
251		}
252
253		/// <summary>
254		/// Get the directories in the given path.
255		/// </summary>
256		/// <param name="path">Path</param>
257		/// <param name="searchPattern">Search pattern to find specific
258		/// directories only.</param>
259		/// <returns>Array of sub directories of path</returns>
260		public static string[] GetDirectories(string path, string searchPattern)
261		{
262			if (Exists(path) == false)
263			{
264				return new string[0];
265			}
266
267			return GetDirectoriesCallback(path, searchPattern);
268		}
269		#endregion
270
271		#region GetDirectoriesRecursive (Static)
272		/// <summary>
273		/// Get all directories and sub directories in the given path recursively.
274		/// </summary>
275		/// <param name="path">Path</param>
276		/// <returns>List of all directories found</returns>
277		public static string[] GetDirectoriesRecursive(string path)
278		{
279			return GetDirectoriesRecursive(path, "*");
280		}
281
282		/// <summary>
283		/// Get all directories and sub directories in the given path recursively.
284		/// </summary>
285		/// <param name="path">Path</param>
286		/// <param name="searchPattern">Search Pattern</param>
287		/// <returns>List of all directories found</returns>
288		public static string[] GetDirectoriesRecursive(string path,
289			string searchPattern)
290		{
291			if (Exists(path) == false)
292			{
293				return new string[0];
294			}
295
296			return GetDirectoriesRecursiveCallback(path, searchPattern);
297		}
298		#endregion
299
300		#region GetParentDirectory (Static)
301		/// <summary>
302		/// Gets the parent directory of the given directory.
303		/// </summary>
304		/// <param name="directory">The path of the current folder</param>
305		/// <param name="parentDirectory">The path of the parent directory.</param>
306		/// <returns>Returns 'true' if there is a parent directory.</returns>
307		public static bool GetParentDirectory(this string directory,
308			out string parentDirectory)
309		{
310			parentDirectory = FileHelper.GetDirectoryPath(directory);
311
312			return parentDirectory != directory;
313		}
314		#endregion
315
316		#region ComparePaths (Static)
317		/// <summary>
318		/// Compare two paths, ignoring if they use \\ or / and if
319		/// something is written in big or small letters. We also check the full
320		/// path so if we have something like .. or . this won't affect the
321		/// comparison.
322		/// </summary>
323		/// <param name="path1">First path.</param>
324		/// <param name="path2">Second path.</param>
325		/// <returns>True if the paths are equal.</returns>
326		public static bool ComparePaths(string path1, string path2)
327		{
328			// Validation
329			if (String.IsNullOrEmpty(path1) ||
330			    String.IsNullOrEmpty(path2))
331			{
332				return false;
333			}
334
335			DirectoryInfo info1 = new DirectoryInfo(path1);
336			DirectoryInfo info2 = new DirectoryInfo(path2);
337
338			return String.Compare(
339				info1.FullName.TrimEnd('\\'),
340				info2.FullName.TrimEnd('\\'),
341				StringComparison.InvariantCultureIgnoreCase) == 0 &&
342			       String.Compare(
343			       	Path.GetFullPath(path1).ToUpperInvariant().TrimEnd('\\'),
344			       	Path.GetFullPath(path2).ToUpperInvariant().TrimEnd('\\'),
345			       	StringComparison.InvariantCultureIgnoreCase) == 0;
346
347			//path1 = path1.Replace("\\", "/").ToLower();
348			//path2 = path2.Replace("\\", "/").ToLower();
349			//return path1 == path2;
350		}
351		#endregion
352
353		#region IncludeTrailingBackslash (Static)
354		/// <summary>
355		/// Include trailing backslash. Makes sure the directory ends with "\".
356		/// </summary>
357		/// <param name="directory">Directory</param>
358		/// <returns>String that always ends with a backslash</returns>
359		public static string IncludeTrailingBackslash(string directory)
360		{
361			if (directory.Length == 0 ||
362			    directory[directory.Length - 1] != '\\')
363			{
364				directory += @"\";
365			}
366			return directory;
367		}
368		#endregion
369
370		#region ExcludeTrailingBackslash (Static)
371		/// <summary>
372		/// Exclude last trailing backslash from a directory.
373		/// </summary>
374		/// <param name="directory">Directory</param>
375		/// <returns>String without a trailing backslash</returns>
376		public static string ExcludeTrailingBackslash(string directory)
377		{
378			if (directory[directory.Length - 1] == '\\')
379			{
380				return directory.Substring(0, directory.Length - 1);
381			}
382			return directory;
383		}
384		#endregion
385
386		#region CopyDirectory (Static)
387		/// <summary>
388		/// Copy directory and all files over to destinationPath.
389		/// </summary>
390		/// <param name="destinationPath">Destination Path</param>
391		/// <param name="sourcePath">Source Path</param>
392		/// <returns>True if the directory was copied successfully</returns>
393		public static bool CopyDirectory(string sourcePath,
394			string destinationPath)
395		{
396			bool ret = false;
397			try
398			{
399				string separator = Path.DirectorySeparatorChar.ToString();
400				sourcePath =
401					sourcePath.EndsWith(separator)
402						? sourcePath
403						: sourcePath + separator;
404
405				destinationPath =
406					destinationPath.EndsWith(separator)
407						? destinationPath
408						: destinationPath + separator;
409
410				if (Exists(sourcePath))
411				{
412					if (Exists(destinationPath) == false)
413					{
414						CreateDirectory(destinationPath);
415					}
416
417					foreach (string fls in GetFiles(sourcePath, "*"))
418					{
419						FileInfo flinfo = new FileInfo(fls);
420						flinfo.CopyTo(destinationPath + flinfo.Name, true);
421						if (FileHelper.CompareFiles(destinationPath + flinfo.Name, fls) ==
422						    false)
423						{
424							throw new Exception(
425								"Failed to copy a file (" +flinfo.Name +
426								"). Source and destination files are not equal!");
427						}
428					}
429					ret = true;
430					foreach (string drs in GetDirectories(sourcePath))
431					{
432						DirectoryInfo drinfo = new DirectoryInfo(drs);
433						if (CopyDirectory(drs, destinationPath + drinfo.Name) == false)
434						{
435							ret = false;
436						}
437					}
438				}
439			}
440			catch // (Exception ex)
441			{
442				ret = false;
443			}
444
445			return ret;
446		}
447		#endregion
448
449		#region MoveDirectory (Static)
450		/// <summary>
451		/// Move directory and all files in it to destinationPath.
452		/// </summary>
453		/// <param name="destinationPath">Destination Path</param>
454		/// <param name="sourcePath">Source Path</param>
455		/// <returns>True if the move was successful</returns>
456		public static bool MoveDirectory(string sourcePath,
457			string destinationPath)
458		{
459			bool ret = false;
460			try
461			{
462				string separator = Path.DirectorySeparatorChar.ToString();
463				sourcePath = sourcePath.EndsWith(separator)
464				             	? sourcePath
465				             	: sourcePath + separator;
466
467				destinationPath = destinationPath.EndsWith(separator)
468				                  	? destinationPath
469				                  	: destinationPath + separator;
470
471				if (Exists(sourcePath))
472				{
473					if (Exists(destinationPath) == false)
474					{
475						CreateDirectory(destinationPath);
476					}
477
478					foreach (string fls in GetFiles(sourcePath, "*"))
479					{
480						FileInfo flinfo = new FileInfo(fls);
481						flinfo.MoveTo(destinationPath + flinfo.Name);
482					}
483
484					foreach (string drs in Directory.GetDirectories(sourcePath))
485					{
486						DirectoryInfo drinfo = new DirectoryInfo(drs);
487						if (MoveDirectory(drs, destinationPath + drinfo.Name) == false)
488						{
489							ret = false;
490						}
491					}
492				}
493
494				if (Exists(sourcePath))
495				{
496					SafeDelete(sourcePath);
497				}
498				ret = true;
499			}
500			catch // (Exception ex)
501			{
502				ret = false;
503			}
504
505			return ret;
506		}
507		#endregion
508
509		#region SafeDelete (Static)
510		/// <summary>
511		/// Delete directory and warn if we are unable to delete files.
512		/// </summary>
513		/// <param name="path">Path</param>
514		/// <returns>True if the deletion succeeded</returns>
515		public static bool SafeDelete(string path)
516		{
517			return Delete(path, true);
518		}
519		#endregion
520
521		#region Delete (Static)
522		/// <summary>
523		/// Delete directory and optionally warn if we are unable to delete files.
524		/// </summary>
525		/// <param name="path">Path to delete</param>
526		/// <param name="warnIfFailing">
527		/// Warn if any file fails to be deleted (usually happens when files are
528		/// still open and locked).
529		/// </param>
530		/// <returns>
531		/// True if the deletion succeeded, if the directory does not exist this
532		/// method simply returns false.
533		/// </returns>
534		public static bool Delete(string path, bool warnIfFailing)
535		{
536			if (Exists(path) == false)
537			{
538				return true;
539			}
540
541			try
542			{
543				foreach (string file in GetFilesRecursive(path, "*.*"))
544				{
545					try
546					{
547						FileHelper.SafeDelete(file);
548					}
549					catch (Exception)
550					{
551						if (warnIfFailing)
552						{
553							Log.Warning("Unable to delete file: " + file);
554						}
555					}
556				}
557
558				DeleteCallback(path);
559
560				return true;
561			}
562			catch (Exception ex)
563			{
564				if (warnIfFailing)
565				{
566					Log.Warning("Failed to delete directory " + path + ": " + ex);
567				}
568				return false;
569			}
570		}
571		#endregion
572
573		#region Internal
574
575		#region ExistsCallback (Internal)
576		internal static ExistsDelegate ExistsCallback;
577		#endregion
578
579		#region GetBaseDirectoryCallback (Internal)
580		/// <summary>
581		/// Callback for getting the base directory. On Windows this is just
582		/// Directory.GetBaseDirectory.
583		/// </summary>
584		internal static GetBaseDirectoryDelegate GetBaseDirectoryCallback;
585		#endregion
586
587		#region GetCurrentDirectoryCallback (Internal)
588		/// <summary>
589		/// Callback for getting the current directory. On Windows this is just
590		/// Directory.GetCurrentDirectory.
591		/// </summary>
592		internal static GetCurrentDirectoryDelegate GetCurrentDirectoryCallback;
593		#endregion
594
595		#region SetCurrentDirectoryCallback (Internal)
596		/// <summary>
597		/// Callback for setting the current directory. On Windows this is just
598		/// Directory.SetCurrentDirectory.
599		/// </summary>
600		internal static SetCurrentDirectoryDelegate SetCurrentDirectoryCallback;
601		#endregion
602
603		#region CreateDirectoryCallback (Internal)
604		/// <summary>
605		/// Callback for creating a new directory. On Windows this is just
606		/// Directory.Create.
607		/// </summary>
608		internal static CreateDirectoryDelegate CreateDirectoryCallback;
609		#endregion
610
611		#region GetFilesCallback (Internal)
612		/// <summary>
613		/// Callback for getting all files in a directory. On Windows this is just
614		/// Directory.GetFiles.
615		/// </summary>
616		internal static GetFilesDelegate GetFilesCallback;
617		#endregion
618
619		#region GetDirectoriesCallback (Internal)
620		internal static GetDirectoriesDelegate GetDirectoriesCallback;
621		#endregion
622
623		#region GetDirectoriesRecursiveCallback (Internal)
624		internal static GetDirectoriesRecursiveDelegate
625			GetDirectoriesRecursiveCallback;
626		#endregion
627
628		#region DeleteCallback (Internal)
629		internal static DeleteDelegate DeleteCallback;
630		#endregion
631
632		#endregion
633
634		#region Constructors
635		/// <summary>
636		/// Static constructor to setup all the needed callbacks.
637		/// </summary>
638		static DirectoryHelper()
639		{
640			ExistsCallback = Directory.Exists;
641			SetCurrentDirectoryCallback = Directory.SetCurrentDirectory;
642			GetDirectoriesCallback = Directory.GetDirectories;
643			GetCurrentDirectoryCallback = Directory.GetCurrentDirectory;
644			GetFilesCallback = Directory.GetFiles;
645
646			#region CreateDirectoryCallback
647			CreateDirectoryCallback = delegate(string directoryPath)
648			{
649				Directory.CreateDirectory(directoryPath);
650			};
651			#endregion
652
653			#region GetBaseDirectoryCallback
654			GetBaseDirectoryCallback = delegate
655			{
656				return AppDomain.CurrentDomain.BaseDirectory;
657			};
658			#endregion
659
660			#region GetDirectoriesRecursiveCallback
661			GetDirectoriesRecursiveCallback = delegate(string path,
662				string searchPattern)
663			{
664				return Directory.GetDirectories(path, searchPattern,
665					SearchOption.AllDirectories);
666			};
667			#endregion
668
669			#region DeleteCallback
670			DeleteCallback = delegate(string path)
671			{
672				Directory.Delete(path, true);
673			};
674			#endregion
675		}
676		#endregion
677
678		/// <summary>
679		/// Tests for the DirectoryHelper class
680		/// </summary>
681		internal class DirectoryHelperTests
682		{
683			#region CopyDir (Static)
684			/// <summary>
685			/// Copy directory. Note: Too slow for a dynamic unit test.
686			/// </summary>
687			[Test, Category("LongRunning")]
688			public static void CopyDir()
689			{
690				// Only do this test if C:\testing and C:\copytest do not exist!
691				Assert.False(Directory.Exists("C:\\testing\\"));
692				Assert.False(Directory.Exists("C:\\copytest\\"));
693
694				Directory.CreateDirectory("C:\\testing\\");
695				Directory.CreateDirectory("C:\\testing\\bla\\");
696				File.Create("C:\\testing\\test.txt").Close();
697				File.Create("C:\\testing\\bla\\test.txt").Close();
698
699				Assert.True(CopyDirectory("C:\\testing\\", "C:\\copytest\\"),
700					"Copy Directory");
701
702				Assert.True(File.Exists("C:\\copytest\\test.txt"), "File Exists");
703				Assert.True(File.Exists("C:\\copytest\\bla\\test.txt"), "File Exists");
704
705				Directory.Delete("C:\\testing\\", true);
706				Directory.Delete("C:\\copytest\\", true);
707			}
708			#endregion
709
710			#region GetFilesRecursive (Static)
711			/// <summary>
712			/// Test GetFilesRecursive
713			/// </summary>
714			[Test, Category("LongRunning")]
715			public static void GetFilesRecursive()
716			{
717				string deltaBasePath =
718					Exists(@"C:\code\Delta")
719						? @"C:\code\Delta"
720						: @"C:\Development\Delta";
721				string rootPath = deltaBasePath + @"\Engine\";
722
723				string[] result = DirectoryHelper.GetFilesRecursive(rootPath, "*.cs");
724				Assert.True((rootPath + "Application.cs").Contains(result));
725				Assert.False((rootPath + "blubbb.cs").Contains(result));
726
727				result = DirectoryHelper.GetFilesRecursive(rootPath,
728					"Delta.Engine.csproj");
729				Assert.Equal(result.Length, 1);
730				Assert.Equal(result[0], rootPath + "Delta.Engine.csproj");
731			}
732			#endregion
733
734			#region TestGetFilesMultiPattern (Static)
735			/// <summary>
736			/// Test get files multi pattern
737			/// </summary>
738			[Test, Category("LongRunning")]
739			public static void TestGetFilesMultiPattern()
740			{
741				string[] files = GetFilesMultiPattern(@"C:\code\Delta\",
742					"*.sln|*.suo");
743				foreach (string file in files)
744				{
745					Console.WriteLine(file);
746				}
747			}
748			#endregion
749
750			#region ComparePaths (Static)
751			/// <summary>
752			/// Test the ComparePaths method.
753			/// </summary>
754			[Test]
755			public static void ComparePaths()
756			{
757				Assert.True(DirectoryHelper.ComparePaths(
758					"C:\\code\\Delta", "C:\\code\\Delta"));
759
760				Assert.True(DirectoryHelper.ComparePaths(
761					"C:\\code\\Delta", "C:/code/Delta"));
762
763				Assert.True(DirectoryHelper.ComparePaths(
764					"c:\\code\\delta", "C:/CODE/DELTA"));
765
766				Assert.False(DirectoryHelper.ComparePaths(
767					"C:\\code\\Delta", "C:\\code\\Delt"));
768
769				// Special cases
770				Assert.True(DirectoryHelper.ComparePaths(
771					"C:\\code\\Delta\\..\\..\\.\\code\\Delta", "C:\\code\\Delta"));
772
773				Assert.True(DirectoryHelper.ComparePaths(
774					"C:/code\\Delta", "C:\\code/Delta"));
775
776				Assert.True(DirectoryHelper.ComparePaths(
777					"C:/code\\..\\code\\Delta", "C:\\code/./Delta"));
778			}
779			#endregion
780
781			#region GetParentDirectory
782			/// <summary>
783			/// Get parent directory
784			/// </summary>
785			[Test]
786			public void GetParentDirectory()
787			{
788				string path = @"C:\Windows\System32";
789
790				string parentPath;
791				Assert.True(path.GetParentDirectory(out parentPath));
792				Assert.Equal(parentPath, @"C:\Windows");
793
794				Assert.True(parentPath.GetParentDirectory(out parentPath));
795				Assert.Equal(parentPath, @"C:");
796
797				Assert.False(parentPath.GetParentDirectory(out parentPath));
798				Assert.Equal(parentPath, @"C:");
799			}
800			#endregion
801		}
802	}
803}