UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
PathTests.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
8#if WITH_LOW_LEVEL_TESTS
9#include "TestCommon/Expectations.h"
10#endif
11
12#if WITH_TESTS
13
14template<class PathType, class StringType>
16{
17 auto Run = [](const TCHAR* Path, bool bExpectedAllCollapsed, const TCHAR* Expected)
18 {
19 // Run test
20 StringType Actual;
21 StringType IfPossibleActual;
22 Actual += Path;
24 const bool bAllCollapsed = PathType::CollapseRelativeDirectories(
25 Actual, false /* bCollapseAllPossible */);
26 const bool bIfPossibleAllCollapsed = PathType::CollapseRelativeDirectories(
27 IfPossibleActual, true /* bCollapseAllPossible */);
28
29 auto IsExpectedText = [Expected](const TCHAR* Actual)
30 {
31 return FCString::Strcmp(Actual, Expected) == 0;
32 };
34 {
35 // If we're looking for a result, make sure it was returned correctly
37 {
38 FAIL_CHECK(FString::Printf(TEXT("CollapseRelativeDirectories('%s', false) failed (got (%s, '%s'), expected (%s, '%s'))."),
40 }
42 {
43 FAIL_CHECK(FString::Printf(TEXT("CollapseRelativeDirectories('%s', true) failed (got (%s, '%s'), expected (%s, '%s'))."),
45 }
46 }
47 else
48 {
49 // Otherwise, make sure it failed
50 if (bAllCollapsed)
51 {
52 // Some of the string might have been collapsed before finding out in has an incollapsible piece
53 // The only well-defined option for those cases is to leave the original string unaltered, but
54 // enforcing that contract is too expensive, so we don't provide that contract and instead we
55 // only guarantee that the modified path is equivalent, perhaps with some .. and . collapsed.
56 // We don't currently validate that equivalency on our test cases, because it is difficult to calculate.
57 FAIL_CHECK(FString::Printf(TEXT("Path '%s' failed CollapseRelativeDirectories (got (%s, '%s'), expected (%s, '<anyvalue>'))."),
59 }
61 {
62 FAIL_CHECK(FString::Printf(TEXT("Path '%s' failed CollapseRelativeDirectoriesIfPossible (got (%s, '%s'), expected (%s, '%s'))."),
64 }
65 }
66 };
67
68 Run(TEXT(".."), false, TEXT(".."));
69 Run(TEXT("/.."), false, TEXT("/.."));
70 Run(TEXT("./"), true, TEXT(""));
71 Run(TEXT("./file.txt"), true, TEXT("file.txt"));
72 Run(TEXT("/."), true, TEXT("/."));
73 Run(TEXT("Folder"), true, TEXT("Folder"));
74 Run(TEXT("/Folder"), true, TEXT("/Folder"));
75 Run(TEXT("C:/Folder"), true, TEXT("C:/Folder"));
76 Run(TEXT("C:/Folder/.."), true, TEXT("C:")); // removing the leading slash is incorrect but legacy behavior, we should fix eventually
77 Run(TEXT("C:/Folder/../"), true, TEXT("C:/"));
78 Run(TEXT("C:/Folder/../file.txt"), true, TEXT("C:/file.txt"));
79 Run(TEXT("Folder/.."), true, TEXT(""));
80 Run(TEXT("Folder/../"), true, TEXT(""));
81 Run(TEXT("Folder/../file.txt"), true, TEXT("file.txt"));
82 Run(TEXT("/Folder/.."), true, TEXT("")); // removing the leading slash is incorrect but legacy behavior, we should fix eventually
83 Run(TEXT("/Folder/../"), true, TEXT("/"));
84 Run(TEXT("/Folder/../file.txt"), true, TEXT("/file.txt"));
85 Run(TEXT("Folder/../.."), false, TEXT(".."));
86 Run(TEXT("Folder/../../"), false, TEXT("../"));
87 Run(TEXT("Folder/../../file.txt"), false, TEXT("../file.txt"));
88 Run(TEXT("C:/.."), false, TEXT("C:/.."));
89 Run(TEXT("C:/."), true, TEXT("C:/."));
90 Run(TEXT("C:/./"), true, TEXT("C:/"));
91 Run(TEXT("C:/./file.txt"), true, TEXT("C:/file.txt"));
92 Run(TEXT("C:/Folder1/../Folder2"), true, TEXT("C:/Folder2"));
93 Run(TEXT("C:/Folder1/../Folder2/"), true, TEXT("C:/Folder2/"));
94 Run(TEXT("C:/Folder1/../Folder2/file.txt"), true, TEXT("C:/Folder2/file.txt"));
95 Run(TEXT("C:/Folder1/../Folder2/../.."), false, TEXT("C:/.."));
96 Run(TEXT("C:/Folder1/../Folder2/../Folder3"), true, TEXT("C:/Folder3"));
97 Run(TEXT("C:/Folder1/../Folder2/../Folder3/"), true, TEXT("C:/Folder3/"));
98 Run(TEXT("C:/Folder1/../Folder2/../Folder3/file.txt"), true, TEXT("C:/Folder3/file.txt"));
99 Run(TEXT("C:/Folder1/Folder2/../../Folder3"), true, TEXT("C:/Folder3"));
100 Run(TEXT("C:/Folder1/Folder2/../../Folder3/"), true, TEXT("C:/Folder3/"));
101 Run(TEXT("C:/Folder1/Folder2/../../Folder3/file.txt"), true, TEXT("C:/Folder3/file.txt"));
102 Run(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4"), true, TEXT("C:/Folder4"));
103 Run(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4/"), true, TEXT("C:/Folder4/"));
104 Run(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4/file.txt"), true, TEXT("C:/Folder4/file.txt"));
105 Run(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4"), true, TEXT("C:/Folder4"));
106 Run(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4/"), true, TEXT("C:/Folder4/"));
107 Run(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4/file.txt"), true, TEXT("C:/Folder4/file.txt"));
108 Run(TEXT("C:/Folder1/Folder2/.././../Folder4"), true, TEXT("C:/Folder4"));
109 Run(TEXT("C:/Folder1/Folder2/.././../Folder4/"), true, TEXT("C:/Folder4/"));
110 Run(TEXT("C:/Folder1/Folder2/.././../Folder4/file.txt"), true, TEXT("C:/Folder4/file.txt"));
111 Run(TEXT("C:/A/B/.././../C"), true, TEXT("C:/C"));
112 Run(TEXT("C:/A/B/.././../C/"), true, TEXT("C:/C/"));
113 Run(TEXT("C:/A/B/.././../C/file.txt"), true, TEXT("C:/C/file.txt"));
114 Run(TEXT(".svn"), true, TEXT(".svn"));
115 Run(TEXT("/.svn"), true, TEXT("/.svn"));
116 Run(TEXT("./Folder/.svn"), true, TEXT("Folder/.svn"));
117 Run(TEXT("./.svn/../.svn"), true, TEXT(".svn"));
118 Run(TEXT(".svn/./.svn/.././../.svn"), true, TEXT(".svn"));
119 Run(TEXT("C:/Folder1/./Folder2/..Folder3"), true, TEXT("C:/Folder1/Folder2/..Folder3"));
120 Run(TEXT("C:/Folder1/./Folder2/..Folder3/Folder4"), true, TEXT("C:/Folder1/Folder2/..Folder3/Folder4"));
121 Run(TEXT("C:/Folder1/./Folder2/..Folder3/..Folder4"), true, TEXT("C:/Folder1/Folder2/..Folder3/..Folder4"));
122 Run(TEXT("C:/Folder1/./Folder2/..Folder3/Folder4/../Folder5"), true, TEXT("C:/Folder1/Folder2/..Folder3/Folder5"));
123 Run(TEXT("C:/Folder1/..Folder2/Folder3/..Folder4/../Folder5"), true, TEXT("C:/Folder1/..Folder2/Folder3/Folder5"));
124 // Handle .. that need to collapse through duplicate separators
125 Run(TEXT("D:/Root/Engine//../.."), true, TEXT("D:")); // removing the leading slash is incorrect but legacy behavior, we should fix eventually
126 Run(TEXT("D:/Root/Engine////////../.."), true, TEXT("D:")); // removing the leading slash is incorrect but legacy behavior, we should fix eventually
127 Run(TEXT("D:/Root/Engine//../../"), true, TEXT("D:/"));
128 Run(TEXT("D:/Root/Engine////////../../"), true, TEXT("D:/"));
129 Run(TEXT("D:/Root//../.."), false, TEXT("D:/.."));
130 Run(TEXT("D:/Root////////../.."), false, TEXT("D:/.."));
131 // But don't remove a leading // for network share when collapsing
132 Run(TEXT("//.."), true, TEXT("")); // removing the leading network path is incorrect but legacy behavior, we should fix eventually
133 Run(TEXT("//Root/../.."), true, TEXT("")); // removing the leading network path is incorrect but legacy behavior, we should fix eventually
134}
135
136template<class PathType, class StringType>
138{
139 auto Run = [&](const TCHAR* Path, const TCHAR* Expected)
140 {
141 StringType Actual;
142 Actual += Path;
143 PathType::RemoveDuplicateSlashes(Actual);
144 CHECK_EQUALS(TEXT("RemoveDuplicateSlashes"), *Actual, Expected);
145 };
146
147 Run(TEXT(""), TEXT(""));
148 Run(TEXT("C:/Folder/File.txt"), TEXT("C:/Folder/File.txt"));
149 Run(TEXT("C:/Folder/File/"), TEXT("C:/Folder/File/"));
150 Run(TEXT("/"), TEXT("/"));
151 Run(TEXT("//"), TEXT("/"));
152 Run(TEXT("////"), TEXT("/"));
153 Run(TEXT("/Folder/File"), TEXT("/Folder/File"));
154 Run(TEXT("//Folder/File"), TEXT("/Folder/File")); // Don't use on //UNC paths; it will be stripped!
155 Run(TEXT("/////Folder//////File/////"), TEXT("/Folder/File/"));
156 Run(TEXT("\\\\Folder\\\\File\\\\"), TEXT("\\\\Folder\\\\File\\\\")); // It doesn't strip backslash, and we rely on that in some places
157 Run(TEXT("//\\\\//Folder//\\\\//File//\\\\//"), TEXT("/\\\\/Folder/\\\\/File/\\\\/"));
158}
159
160namespace PathTest
161{
162
163struct FTestPair
164{
166 FStringView Expected;
167};
168
169extern const FStringView BaseDir;
170
172
173}
174
175#endif //WITH_TESTS
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
const TCHAR * LexToString(EAnalyticsRecordEventMode Mode)
Definition IAnalyticsProvider.cpp:5
#define CHECK_EQUALS(What, X, Y)
Definition LowLevelTestAdapter.h:143
#define FAIL_CHECK(Message)
Definition LowLevelTestAdapter.h:149
const FColor Path(255, 255, 255)
void Run(FMassRuntimePipeline &RuntimePipeline, FProcessingContext &ProcessingContext)
Definition MassExecutor.cpp:25
static UE_FORCEINLINE_HINT int32 Strcmp(const CharType *String1, const CharType *String2)
Definition CString.h:1018