diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2022-05-26 17:33:15 -0500 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2022-05-31 13:20:44 -0500 |
commit | fb4f8c7108f43d2341ba299424646c4963b21188 (patch) | |
tree | 7f3c907ac5406d2000056f6bcca41d7ae4d3a925 | |
parent | 0f9931107ecf9e1f6714e6fd2cabc76d2ddb1153 (diff) | |
download | wix-fb4f8c7108f43d2341ba299424646c4963b21188.tar.gz wix-fb4f8c7108f43d2341ba299424646c4963b21188.tar.bz2 wix-fb4f8c7108f43d2341ba299424646c4963b21188.zip |
Replace PathIsAbsolute with PathIsRooted and add PathIsFullyQualified.
-rw-r--r-- | src/burn/engine/cache.cpp | 2 | ||||
-rw-r--r-- | src/burn/engine/logging.cpp | 2 | ||||
-rw-r--r-- | src/internal/WixBuildTools.TestSupport.Native/NativeAssert.h | 21 | ||||
-rw-r--r-- | src/internal/WixBuildTools.TestSupport/XunitExtensions/SpecificReturnCodeException.cs | 19 | ||||
-rw-r--r-- | src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs | 8 | ||||
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | 19 | ||||
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/pathutil.cpp | 102 | ||||
-rw-r--r-- | src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | 199 |
8 files changed, 350 insertions, 22 deletions
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index 5d81e1ba..2b7d6ede 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp | |||
@@ -563,7 +563,7 @@ extern "C" HRESULT CacheGetLocalSourcePaths( | |||
563 | fPreferSourcePathLocation = !pCache->fRunningFromCache || FAILED(hr); | 563 | fPreferSourcePathLocation = !pCache->fRunningFromCache || FAILED(hr); |
564 | fTryLastFolder = SUCCEEDED(hr) && sczLastSourceFolder && *sczLastSourceFolder && CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCache->sczSourceProcessFolder, -1, sczLastSourceFolder, -1); | 564 | fTryLastFolder = SUCCEEDED(hr) && sczLastSourceFolder && *sczLastSourceFolder && CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCache->sczSourceProcessFolder, -1, sczLastSourceFolder, -1); |
565 | fTryRelativePath = CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzSourcePath, -1, wzRelativePath, -1); | 565 | fTryRelativePath = CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzSourcePath, -1, wzRelativePath, -1); |
566 | fSourceIsAbsolute = PathIsAbsolute(wzSourcePath); | 566 | fSourceIsAbsolute = PathIsRooted(wzSourcePath); |
567 | 567 | ||
568 | // If the source path provided is a full path, try that first. | 568 | // If the source path provided is a full path, try that first. |
569 | if (fSourceIsAbsolute) | 569 | if (fSourceIsAbsolute) |
diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 1b2bec1f..8e89957b 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp | |||
@@ -140,7 +140,7 @@ extern "C" HRESULT LoggingOpen( | |||
140 | LPCWSTR wzPrefix = sczPrefixFormatted; | 140 | LPCWSTR wzPrefix = sczPrefixFormatted; |
141 | 141 | ||
142 | // Best effort to open default logging. | 142 | // Best effort to open default logging. |
143 | if (PathIsAbsolute(sczPrefixFormatted)) | 143 | if (PathIsRooted(sczPrefixFormatted)) |
144 | { | 144 | { |
145 | hr = PathGetDirectory(sczPrefixFormatted, &sczLoggingBaseFolder); | 145 | hr = PathGetDirectory(sczPrefixFormatted, &sczLoggingBaseFolder); |
146 | ExitOnFailure(hr, "Failed to get parent directory from '%ls'.", sczPrefixFormatted); | 146 | ExitOnFailure(hr, "Failed to get parent directory from '%ls'.", sczPrefixFormatted); |
diff --git a/src/internal/WixBuildTools.TestSupport.Native/NativeAssert.h b/src/internal/WixBuildTools.TestSupport.Native/NativeAssert.h index 62ace4a9..b0206b14 100644 --- a/src/internal/WixBuildTools.TestSupport.Native/NativeAssert.h +++ b/src/internal/WixBuildTools.TestSupport.Native/NativeAssert.h | |||
@@ -64,6 +64,27 @@ namespace TestSupport { | |||
64 | WixAssert::Succeeded(hr, gcnew String(zFormat), formatArgs); | 64 | WixAssert::Succeeded(hr, gcnew String(zFormat), formatArgs); |
65 | } | 65 | } |
66 | 66 | ||
67 | static void SpecificReturnCode(HRESULT hrExpected, HRESULT hr, LPCSTR zFormat, LPCSTR zArg, ... array<LPCSTR>^ zArgs) | ||
68 | { | ||
69 | array<Object^>^ formatArgs = gcnew array<Object^, 1>(zArgs->Length + 1); | ||
70 | formatArgs[0] = NativeAssert::LPSTRToString(zArg); | ||
71 | for (int i = 0; i < zArgs->Length; ++i) | ||
72 | { | ||
73 | formatArgs[i + 1] = NativeAssert::LPSTRToString(zArgs[i]); | ||
74 | } | ||
75 | WixAssert::SpecificReturnCode(hrExpected, hr, gcnew String(zFormat), formatArgs); | ||
76 | } | ||
77 | |||
78 | static void SpecificReturnCode(HRESULT hrExpected, HRESULT hr, LPCSTR zFormat, ... array<LPCWSTR>^ wzArgs) | ||
79 | { | ||
80 | array<Object^>^ formatArgs = gcnew array<Object^, 1>(wzArgs->Length); | ||
81 | for (int i = 0; i < wzArgs->Length; ++i) | ||
82 | { | ||
83 | formatArgs[i] = NativeAssert::LPWSTRToString(wzArgs[i]); | ||
84 | } | ||
85 | WixAssert::SpecificReturnCode(hrExpected, hr, gcnew String(zFormat), formatArgs); | ||
86 | } | ||
87 | |||
67 | static void ValidReturnCode(HRESULT hr, ... array<HRESULT>^ validReturnCodes) | 88 | static void ValidReturnCode(HRESULT hr, ... array<HRESULT>^ validReturnCodes) |
68 | { | 89 | { |
69 | Assert::Contains(hr, (IEnumerable<HRESULT>^)validReturnCodes); | 90 | Assert::Contains(hr, (IEnumerable<HRESULT>^)validReturnCodes); |
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SpecificReturnCodeException.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SpecificReturnCodeException.cs new file mode 100644 index 00000000..c66890f8 --- /dev/null +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SpecificReturnCodeException.cs | |||
@@ -0,0 +1,19 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | namespace WixBuildTools.TestSupport | ||
4 | { | ||
5 | using System; | ||
6 | using Xunit.Sdk; | ||
7 | |||
8 | public class SpecificReturnCodeException : XunitException | ||
9 | { | ||
10 | public SpecificReturnCodeException(int hr, string userMessage) | ||
11 | : base(String.Format("WixAssert.SpecificReturnCode() Failure\r\n" + | ||
12 | "HRESULT: 0x{0:X8}\r\n" + | ||
13 | "Message: {1}", | ||
14 | hr, userMessage)) | ||
15 | { | ||
16 | this.HResult = hr; | ||
17 | } | ||
18 | } | ||
19 | } | ||
diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs index 10156547..1ede55b3 100644 --- a/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs | |||
@@ -52,6 +52,14 @@ namespace WixBuildTools.TestSupport | |||
52 | throw new SkipTestException(message); | 52 | throw new SkipTestException(message); |
53 | } | 53 | } |
54 | 54 | ||
55 | public static void SpecificReturnCode(int hrExpected, int hr, string format, params object[] formatArgs) | ||
56 | { | ||
57 | if (hrExpected != hr) | ||
58 | { | ||
59 | throw new SpecificReturnCodeException(hr, String.Format(format, formatArgs)); | ||
60 | } | ||
61 | } | ||
62 | |||
55 | public static void Succeeded(int hr, string format, params object[] formatArgs) | 63 | public static void Succeeded(int hr, string format, params object[] formatArgs) |
56 | { | 64 | { |
57 | if (0 > hr) | 65 | if (0 > hr) |
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h index 44d36568..602b4a80 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | |||
@@ -166,10 +166,23 @@ DAPI_(HRESULT) PathGetKnownFolder( | |||
166 | ); | 166 | ); |
167 | 167 | ||
168 | /******************************************************************* | 168 | /******************************************************************* |
169 | PathIsAbsolute - returns true if the path is absolute; false | 169 | PathIsFullyQualified - returns true if the path is fully qualified; false otherwise. |
170 | otherwise. | 170 | Note that some rooted paths like C:dir are not fully qualified. |
171 | For example, these are all fully qualified: C:\dir, \\server\share, \\?\C:\dir. | ||
172 | For example, these are not fully qualified: C:dir, C:, \dir, dir, dir\subdir. | ||
171 | *******************************************************************/ | 173 | *******************************************************************/ |
172 | DAPI_(BOOL) PathIsAbsolute( | 174 | DAPI_(BOOL) PathIsFullyQualified( |
175 | __in_z LPCWSTR wzPath, | ||
176 | __out_opt BOOL* pfHasLongPathPrefix | ||
177 | ); | ||
178 | |||
179 | /******************************************************************* | ||
180 | PathIsRooted - returns true if the path is rooted; false otherwise. | ||
181 | Note that some rooted paths like C:dir are not fully qualified. | ||
182 | For example, these are all rooted: C:\dir, C:dir, C:, \dir, \\server\share, \\?\C:\dir. | ||
183 | For example, these are not rooted: dir, dir\subdir. | ||
184 | *******************************************************************/ | ||
185 | DAPI_(BOOL) PathIsRooted( | ||
173 | __in_z LPCWSTR wzPath | 186 | __in_z LPCWSTR wzPath |
174 | ); | 187 | ); |
175 | 188 | ||
diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp index 9823779b..314eab85 100644 --- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp | |||
@@ -20,6 +20,10 @@ | |||
20 | 20 | ||
21 | #define PATH_GOOD_ENOUGH 64 | 21 | #define PATH_GOOD_ENOUGH 64 |
22 | 22 | ||
23 | static BOOL IsValidDriveChar( | ||
24 | __in WCHAR wc | ||
25 | ); | ||
26 | |||
23 | 27 | ||
24 | DAPI_(LPWSTR) PathFile( | 28 | DAPI_(LPWSTR) PathFile( |
25 | __in_z LPCWSTR wzPath | 29 | __in_z LPCWSTR wzPath |
@@ -272,29 +276,30 @@ DAPI_(HRESULT) PathPrefix( | |||
272 | 276 | ||
273 | HRESULT hr = S_OK; | 277 | HRESULT hr = S_OK; |
274 | LPWSTR wzFullPath = *psczFullPath; | 278 | LPWSTR wzFullPath = *psczFullPath; |
279 | BOOL fFullyQualified = FALSE; | ||
280 | BOOL fHasPrefix = FALSE; | ||
275 | SIZE_T cbFullPath = 0; | 281 | SIZE_T cbFullPath = 0; |
276 | 282 | ||
277 | if (((L'a' <= wzFullPath[0] && L'z' >= wzFullPath[0]) || | 283 | fFullyQualified = PathIsFullyQualified(wzFullPath, &fHasPrefix); |
278 | (L'A' <= wzFullPath[0] && L'Z' >= wzFullPath[0])) && | 284 | if (fHasPrefix) |
279 | L':' == wzFullPath[1] && | 285 | { |
280 | L'\\' == wzFullPath[2]) // normal path | 286 | ExitFunction(); |
287 | } | ||
288 | |||
289 | if (fFullyQualified && L':' == wzFullPath[1]) // normal path | ||
281 | { | 290 | { |
282 | hr = StrAllocPrefix(psczFullPath, L"\\\\?\\", 4); | 291 | hr = StrAllocPrefix(psczFullPath, L"\\\\?\\", 4); |
283 | PathExitOnFailure(hr, "Failed to add prefix to file path."); | 292 | PathExitOnFailure(hr, "Failed to add prefix to file path."); |
284 | } | 293 | } |
285 | else if (L'\\' == wzFullPath[0] && L'\\' == wzFullPath[1]) // UNC | 294 | else if (fFullyQualified && L'\\' == wzFullPath[1]) // UNC |
286 | { | 295 | { |
287 | // ensure that we're not already prefixed | 296 | hr = StrSize(*psczFullPath, &cbFullPath); |
288 | if (!(L'?' == wzFullPath[2] && L'\\' == wzFullPath[3])) | 297 | PathExitOnFailure(hr, "Failed to get size of full path."); |
289 | { | ||
290 | hr = StrSize(*psczFullPath, &cbFullPath); | ||
291 | PathExitOnFailure(hr, "Failed to get size of full path."); | ||
292 | 298 | ||
293 | memmove_s(wzFullPath, cbFullPath, wzFullPath + 1, cbFullPath - sizeof(WCHAR)); | 299 | memmove_s(wzFullPath, cbFullPath, wzFullPath + 1, cbFullPath - sizeof(WCHAR)); |
294 | 300 | ||
295 | hr = StrAllocPrefix(psczFullPath, L"\\\\?\\UNC", 7); | 301 | hr = StrAllocPrefix(psczFullPath, L"\\\\?\\UNC", 7); |
296 | PathExitOnFailure(hr, "Failed to add prefix to UNC path."); | 302 | PathExitOnFailure(hr, "Failed to add prefix to UNC path."); |
297 | } | ||
298 | } | 303 | } |
299 | else | 304 | else |
300 | { | 305 | { |
@@ -814,11 +819,66 @@ LExit: | |||
814 | } | 819 | } |
815 | 820 | ||
816 | 821 | ||
817 | DAPI_(BOOL) PathIsAbsolute( | 822 | DAPI_(BOOL) PathIsFullyQualified( |
823 | __in_z LPCWSTR wzPath, | ||
824 | __out_opt BOOL* pfHasLongPathPrefix | ||
825 | ) | ||
826 | { | ||
827 | BOOL fFullyQualified = FALSE; | ||
828 | BOOL fHasLongPathPrefix = FALSE; | ||
829 | |||
830 | if (!wzPath || !wzPath[0] || !wzPath[1]) | ||
831 | { | ||
832 | // There is no way to specify a fully qualified path with one character (or less). | ||
833 | ExitFunction(); | ||
834 | } | ||
835 | |||
836 | if (L'\\' != wzPath[0]) | ||
837 | { | ||
838 | // The only way to specify a fully qualified path that doesn't begin with a slash | ||
839 | // is the drive, colon, slash format (C:\). | ||
840 | if (IsValidDriveChar(wzPath[0]) && | ||
841 | L':' == wzPath[1] && | ||
842 | L'\\' == wzPath[2]) | ||
843 | { | ||
844 | fFullyQualified = TRUE; | ||
845 | } | ||
846 | |||
847 | ExitFunction(); | ||
848 | } | ||
849 | |||
850 | // Non-drive fully qualified paths must start with \\ or \?. | ||
851 | // \??\ is an archaic form of \\?\. | ||
852 | if (L'?' != wzPath[1] && L'\\' != wzPath[1]) | ||
853 | { | ||
854 | ExitFunction(); | ||
855 | } | ||
856 | |||
857 | fFullyQualified = TRUE; | ||
858 | |||
859 | if (L'?' == wzPath[2] && L'\\' == wzPath[3]) | ||
860 | { | ||
861 | fHasLongPathPrefix = TRUE; | ||
862 | } | ||
863 | |||
864 | |||
865 | LExit: | ||
866 | if (pfHasLongPathPrefix) | ||
867 | { | ||
868 | *pfHasLongPathPrefix = fHasLongPathPrefix; | ||
869 | } | ||
870 | |||
871 | return fFullyQualified; | ||
872 | } | ||
873 | |||
874 | |||
875 | DAPI_(BOOL) PathIsRooted( | ||
818 | __in_z LPCWSTR wzPath | 876 | __in_z LPCWSTR wzPath |
819 | ) | 877 | ) |
820 | { | 878 | { |
821 | return wzPath && wzPath[0] && wzPath[1] && (wzPath[0] == L'\\') || (wzPath[1] == L':'); | 879 | return wzPath && |
880 | (wzPath[0] == L'\\' || | ||
881 | IsValidDriveChar(wzPath[0]) && wzPath[1] == L':'); | ||
822 | } | 882 | } |
823 | 883 | ||
824 | 884 | ||
@@ -847,7 +907,7 @@ DAPI_(HRESULT) PathConcatCch( | |||
847 | hr = StrAllocString(psczCombined, wzPath1, cchPath1); | 907 | hr = StrAllocString(psczCombined, wzPath1, cchPath1); |
848 | PathExitOnFailure(hr, "Failed to copy just path1 to output."); | 908 | PathExitOnFailure(hr, "Failed to copy just path1 to output."); |
849 | } | 909 | } |
850 | else if (!wzPath1 || !*wzPath1 || PathIsAbsolute(wzPath2)) | 910 | else if (!wzPath1 || !*wzPath1 || PathIsRooted(wzPath2)) |
851 | { | 911 | { |
852 | hr = StrAllocString(psczCombined, wzPath2, cchPath2); | 912 | hr = StrAllocString(psczCombined, wzPath2, cchPath2); |
853 | PathExitOnFailure(hr, "Failed to copy just path2 to output."); | 913 | PathExitOnFailure(hr, "Failed to copy just path2 to output."); |
@@ -1002,3 +1062,11 @@ LExit: | |||
1002 | 1062 | ||
1003 | return hr; | 1063 | return hr; |
1004 | } | 1064 | } |
1065 | |||
1066 | static BOOL IsValidDriveChar( | ||
1067 | __in WCHAR wc | ||
1068 | ) | ||
1069 | { | ||
1070 | return L'a' <= wc && L'z' >= wc || | ||
1071 | L'A' <= wc && L'Z' >= wc; | ||
1072 | } | ||
diff --git a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp index 6a05a45c..65856514 100644 --- a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp +++ b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | |||
@@ -109,5 +109,204 @@ namespace DutilTests | |||
109 | ReleaseStrArray(rgsczPaths, cPaths); | 109 | ReleaseStrArray(rgsczPaths, cPaths); |
110 | } | 110 | } |
111 | } | 111 | } |
112 | |||
113 | [Fact] | ||
114 | void PathPrefixTest() | ||
115 | { | ||
116 | HRESULT hr = S_OK; | ||
117 | LPWSTR sczPath = NULL; | ||
118 | LPCWSTR rgwzPaths[12] = | ||
119 | { | ||
120 | L"\\\\", L"\\\\?\\UNC\\", | ||
121 | L"C:\\\\foo2", L"\\\\?\\C:\\\\foo2", | ||
122 | L"\\\\a\\b\\", L"\\\\?\\UNC\\a\\b\\", | ||
123 | L"\\\\?\\UNC\\test\\unc\\path\\to\\something", L"\\\\?\\UNC\\test\\unc\\path\\to\\something", | ||
124 | L"\\\\?\\C:\\foo\\bar.txt", L"\\\\?\\C:\\foo\\bar.txt", | ||
125 | L"\\??\\C:\\foo\\bar.txt", L"\\??\\C:\\foo\\bar.txt", | ||
126 | }; | ||
127 | |||
128 | try | ||
129 | { | ||
130 | for (DWORD i = 0; i < countof(rgwzPaths) / 2; i += 2) | ||
131 | { | ||
132 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); | ||
133 | NativeAssert::Succeeded(hr, "Failed to copy string"); | ||
134 | |||
135 | hr = PathPrefix(&sczPath); | ||
136 | NativeAssert::Succeeded(hr, "PathPrefix: {0}", rgwzPaths[i]); | ||
137 | NativeAssert::StringEqual(rgwzPaths[i + 1], sczPath); | ||
138 | } | ||
139 | } | ||
140 | finally | ||
141 | { | ||
142 | ReleaseStr(sczPath); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | [Fact] | ||
147 | void PathPrefixFailureTest() | ||
148 | { | ||
149 | HRESULT hr = S_OK; | ||
150 | LPWSTR sczPath = NULL; | ||
151 | LPCWSTR rgwzPaths[8] = | ||
152 | { | ||
153 | L"\\", | ||
154 | L"C:", | ||
155 | L"C:foo.txt", | ||
156 | L"", | ||
157 | L"\\?", | ||
158 | L"\\dir", | ||
159 | L"dir", | ||
160 | L"dir\\subdir", | ||
161 | }; | ||
162 | |||
163 | try | ||
164 | { | ||
165 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | ||
166 | { | ||
167 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); | ||
168 | NativeAssert::Succeeded(hr, "Failed to copy string"); | ||
169 | |||
170 | hr = PathPrefix(&sczPath); | ||
171 | NativeAssert::SpecificReturnCode(E_INVALIDARG, hr, "PathPrefix: {0}, {1}", rgwzPaths[i], sczPath); | ||
172 | } | ||
173 | } | ||
174 | finally | ||
175 | { | ||
176 | ReleaseStr(sczPath); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | [Fact] | ||
181 | void PathIsRootedAndFullyQualifiedTest() | ||
182 | { | ||
183 | LPCWSTR rgwzPaths[15] = | ||
184 | { | ||
185 | L"\\\\", | ||
186 | L"\\\\\\", | ||
187 | L"C:\\", | ||
188 | L"C:\\\\", | ||
189 | L"C:\\foo1", | ||
190 | L"C:\\\\foo2", | ||
191 | L"\\\\test\\unc\\path\\to\\something", | ||
192 | L"\\\\a\\b\\c\\d\\e", | ||
193 | L"\\\\a\\b\\", | ||
194 | L"\\\\a\\b", | ||
195 | L"\\\\test\\unc", | ||
196 | L"\\\\Server", | ||
197 | L"\\\\Server\\Foo.txt", | ||
198 | L"\\\\Server\\Share\\Foo.txt", | ||
199 | L"\\\\Server\\Share\\Test\\Foo.txt", | ||
200 | }; | ||
201 | |||
202 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | ||
203 | { | ||
204 | ValidateFullyQualifiedPath(rgwzPaths[i], TRUE, FALSE); | ||
205 | ValidateRootedPath(rgwzPaths[i], TRUE); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | [Fact] | ||
210 | void PathIsRootedAndFullyQualifiedWithPrefixTest() | ||
211 | { | ||
212 | LPCWSTR rgwzPaths[6] = | ||
213 | { | ||
214 | L"\\\\?\\UNC\\test\\unc\\path\\to\\something", | ||
215 | L"\\\\?\\UNC\\test\\unc", | ||
216 | L"\\\\?\\UNC\\a\\b1", | ||
217 | L"\\\\?\\UNC\\a\\b2\\", | ||
218 | L"\\\\?\\C:\\foo\\bar.txt", | ||
219 | L"\\??\\C:\\foo\\bar.txt", | ||
220 | }; | ||
221 | |||
222 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | ||
223 | { | ||
224 | ValidateFullyQualifiedPath(rgwzPaths[i], TRUE, TRUE); | ||
225 | ValidateRootedPath(rgwzPaths[i], TRUE); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | [Fact] | ||
230 | void PathIsRootedButNotFullyQualifiedTest() | ||
231 | { | ||
232 | LPCWSTR rgwzPaths[7] = | ||
233 | { | ||
234 | L"\\", | ||
235 | L"a:", | ||
236 | L"A:", | ||
237 | L"z:", | ||
238 | L"Z:", | ||
239 | L"C:foo.txt", | ||
240 | L"\\dir", | ||
241 | }; | ||
242 | |||
243 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | ||
244 | { | ||
245 | ValidateFullyQualifiedPath(rgwzPaths[i], FALSE, FALSE); | ||
246 | ValidateRootedPath(rgwzPaths[i], TRUE); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | [Fact] | ||
251 | void PathIsNotRootedAndNotFullyQualifiedTest() | ||
252 | { | ||
253 | LPCWSTR rgwzPaths[9] = | ||
254 | { | ||
255 | NULL, | ||
256 | L"", | ||
257 | L"dir", | ||
258 | L"dir\\subdir", | ||
259 | L"@:\\foo", // 064 = @ 065 = A | ||
260 | L"[:\\\\", // 091 = [ 090 = Z | ||
261 | L"`:\\foo ", // 096 = ` 097 = a | ||
262 | L"{:\\\\", // 123 = { 122 = z | ||
263 | L"[:", | ||
264 | }; | ||
265 | |||
266 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | ||
267 | { | ||
268 | ValidateFullyQualifiedPath(rgwzPaths[i], FALSE, FALSE); | ||
269 | ValidateRootedPath(rgwzPaths[i], FALSE); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | void ValidateFullyQualifiedPath(LPCWSTR wzPath, BOOL fExpected, BOOL fExpectedHasPrefix) | ||
274 | { | ||
275 | BOOL fHasLongPathPrefix = FALSE; | ||
276 | BOOL fRooted = PathIsFullyQualified(wzPath, &fHasLongPathPrefix); | ||
277 | String^ message = String::Format("IsFullyQualified: {0}", gcnew String(wzPath)); | ||
278 | if (fExpected) | ||
279 | { | ||
280 | Assert::True(fRooted, message); | ||
281 | } | ||
282 | else | ||
283 | { | ||
284 | Assert::False(fRooted, message); | ||
285 | } | ||
286 | |||
287 | message = String::Format("HasLongPathPrefix: {0}", gcnew String(wzPath)); | ||
288 | if (fExpectedHasPrefix) | ||
289 | { | ||
290 | Assert::True(fHasLongPathPrefix, message); | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | Assert::False(fHasLongPathPrefix, message); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | void ValidateRootedPath(LPCWSTR wzPath, BOOL fExpected) | ||
299 | { | ||
300 | BOOL fRooted = PathIsRooted(wzPath); | ||
301 | String^ message = String::Format("IsRooted: {0}", gcnew String(wzPath)); | ||
302 | if (fExpected) | ||
303 | { | ||
304 | Assert::True(fRooted, message); | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | Assert::False(fRooted, message); | ||
309 | } | ||
310 | } | ||
112 | }; | 311 | }; |
113 | } | 312 | } |