1 // ***********************************************************************
2 // Copyright (c) 2008 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
32 using NUnit.Framework.Internal;
34 namespace NUnit.Framework.Constraints
36 #region PathConstraint
38 /// PathConstraint serves as the abstract base of constraints
39 /// that operate on paths and provides several helper methods.
41 public abstract class PathConstraint : StringConstraint
43 private const char WindowsDirectorySeparatorChar = '\\';
44 private const char NonWindowsDirectorySeparatorChar = '/';
45 private static readonly char[] DirectorySeparatorChars = new char[] { WindowsDirectorySeparatorChar, NonWindowsDirectorySeparatorChar };
48 /// Construct a PathConstraint for a give expected path
50 /// <param name="expected">The expected path</param>
51 protected PathConstraint(string expected)
54 this.expected = expected;
55 this.caseInsensitive = Path.DirectorySeparatorChar == WindowsDirectorySeparatorChar;
59 /// Modifies the current instance to be case-sensitive
62 public PathConstraint RespectCase
64 get { caseInsensitive = false; return this; }
68 /// Returns the string representation of this constraint
70 protected override string GetStringRepresentation()
72 return string.Format("<{0} \"{1}\" {2}>", DisplayName.ToLower(), expected, caseInsensitive ? "ignorecase" : "respectcase");
75 #region Helper Methods
77 /// Canonicalize the provided path
79 /// <param name="path"></param>
80 /// <returns>The path in standardized form</returns>
81 protected string Canonicalize(string path)
83 if (Path.DirectorySeparatorChar != Path.AltDirectorySeparatorChar)
84 path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
86 string leadingSeparators = "";
88 foreach (char c in path)
90 if (c == WindowsDirectorySeparatorChar || c == NonWindowsDirectorySeparatorChar)
92 leadingSeparators += Path.DirectorySeparatorChar;
98 string[] parts = path.Split(DirectorySeparatorChars, StringSplitOptions.RemoveEmptyEntries);
100 string[] parts = path.Split(DirectorySeparatorChars);
104 bool shifting = false;
105 foreach (string part in parts)
127 return leadingSeparators + String.Join(Path.DirectorySeparatorChar.ToString(), parts, 0, count);
131 /// Test whether one path in canonical form is a subpath of another path
133 /// <param name="path1">The first path - supposed to be the parent path</param>
134 /// <param name="path2">The second path - supposed to be the child path</param>
135 /// <returns></returns>
136 protected bool IsSubPath(string path1, string path2)
138 int length1 = path1.Length;
139 int length2 = path2.Length;
141 // if path1 is longer or equal, then path2 can't be a subpath
142 if (length1 >= length2)
145 // path 2 is longer than path 1: see if initial parts match
146 if (!StringUtil.StringsEqual(path1, path2.Substring(0, length1), caseInsensitive))
149 // must match through or up to a directory separator boundary
150 return path2[length1 - 1] == Path.DirectorySeparatorChar ||
151 path2[length1] == Path.DirectorySeparatorChar;