xrpld
Loading...
Searching...
No Matches
tests/libxrpl/basics/StringUtilities.cpp
1#include <xrpl/basics/StringUtilities.h>
2
3#include <xrpl/basics/Slice.h>
4#include <xrpl/basics/ToString.h>
5
6#include <gtest/gtest.h>
7
8#include <string>
9
10namespace xrpl {
11
12class StringUtilitiesTest : public ::testing::Test
13{
14public:
15 static void
16 testUnHexSuccess(std::string const& strIn, std::string const& strExpected)
17 {
18 auto rv = strUnHex(strIn);
19 EXPECT_TRUE(rv);
20
21 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
22 EXPECT_EQ(makeSlice(*rv), makeSlice(strExpected));
23 }
24
25 static void
27 {
28 auto rv = strUnHex(strIn);
29 EXPECT_FALSE(rv);
30 }
31};
32
34{
35 testUnHexSuccess("526970706c6544", "RippleD");
36 testUnHexSuccess("A", "\n");
37 testUnHexSuccess("0A", "\n");
38 testUnHexSuccess("D0A", "\r\n");
39 testUnHexSuccess("0D0A", "\r\n");
40 testUnHexSuccess("200D0A", " \r\n");
41 testUnHexSuccess("282A2B2C2D2E2F29", "(*+,-./)");
42
43 // Check for things which contain some or only invalid characters
44 testUnHexFailure("123X");
45 testUnHexFailure("V");
46 testUnHexFailure("XRP");
47}
48
50{
51 // Expected passes.
52 {
53 ParsedUrl pUrl;
54 EXPECT_TRUE(parseUrl(pUrl, "scheme://"));
55 EXPECT_EQ(pUrl.scheme, "scheme");
56 EXPECT_TRUE(pUrl.username.empty());
57 EXPECT_TRUE(pUrl.password.empty());
58 EXPECT_TRUE(pUrl.domain.empty());
59 EXPECT_FALSE(pUrl.port);
60 // RFC 3986:
61 // > In general, a URI that uses the generic syntax for authority
62 // with an empty path should be normalized to a path of "/".
63 // Do we want to normalize paths?
64 EXPECT_TRUE(pUrl.path.empty());
65 }
66
67 {
68 ParsedUrl pUrl;
69 EXPECT_TRUE(parseUrl(pUrl, "scheme:///"));
70 EXPECT_EQ(pUrl.scheme, "scheme");
71 EXPECT_TRUE(pUrl.username.empty());
72 EXPECT_TRUE(pUrl.password.empty());
73 EXPECT_TRUE(pUrl.domain.empty());
74 EXPECT_FALSE(pUrl.port);
75 EXPECT_EQ(pUrl.path, "/");
76 }
77
78 {
79 ParsedUrl pUrl;
80 EXPECT_TRUE(parseUrl(pUrl, "lower://domain"));
81 EXPECT_EQ(pUrl.scheme, "lower");
82 EXPECT_TRUE(pUrl.username.empty());
83 EXPECT_TRUE(pUrl.password.empty());
84 EXPECT_EQ(pUrl.domain, "domain");
85 EXPECT_FALSE(pUrl.port);
86 EXPECT_TRUE(pUrl.path.empty());
87 }
88
89 {
90 ParsedUrl pUrl;
91 EXPECT_TRUE(parseUrl(pUrl, "UPPER://domain:234/"));
92 EXPECT_EQ(pUrl.scheme, "upper");
93 EXPECT_TRUE(pUrl.username.empty());
94 EXPECT_TRUE(pUrl.password.empty());
95 EXPECT_EQ(pUrl.domain, "domain");
96 EXPECT_EQ(*pUrl.port, 234); // NOLINT(bugprone-unchecked-optional-access)
97 EXPECT_EQ(pUrl.path, "/");
98 }
99
100 {
101 ParsedUrl pUrl;
102 EXPECT_TRUE(parseUrl(pUrl, "Mixed://domain/path"));
103 EXPECT_EQ(pUrl.scheme, "mixed");
104 EXPECT_TRUE(pUrl.username.empty());
105 EXPECT_TRUE(pUrl.password.empty());
106 EXPECT_EQ(pUrl.domain, "domain");
107 EXPECT_FALSE(pUrl.port);
108 EXPECT_EQ(pUrl.path, "/path");
109 }
110
111 {
112 ParsedUrl pUrl;
113 EXPECT_TRUE(parseUrl(pUrl, "scheme://[::1]:123/path"));
114 EXPECT_EQ(pUrl.scheme, "scheme");
115 EXPECT_TRUE(pUrl.username.empty());
116 EXPECT_TRUE(pUrl.password.empty());
117 EXPECT_EQ(pUrl.domain, "::1");
118 EXPECT_EQ(*pUrl.port, 123); // NOLINT(bugprone-unchecked-optional-access)
119 EXPECT_EQ(pUrl.path, "/path");
120 }
121
122 {
123 ParsedUrl pUrl;
124 EXPECT_TRUE(parseUrl(pUrl, "scheme://user:pass@domain:123/abc:321"));
125 EXPECT_EQ(pUrl.scheme, "scheme");
126 EXPECT_EQ(pUrl.username, "user");
127 EXPECT_EQ(pUrl.password, "pass");
128 EXPECT_EQ(pUrl.domain, "domain");
129 EXPECT_EQ(*pUrl.port, 123); // NOLINT(bugprone-unchecked-optional-access)
130 EXPECT_EQ(pUrl.path, "/abc:321");
131 }
132
133 {
134 ParsedUrl pUrl;
135 EXPECT_TRUE(parseUrl(pUrl, "scheme://user@domain:123/abc:321"));
136 EXPECT_EQ(pUrl.scheme, "scheme");
137 EXPECT_EQ(pUrl.username, "user");
138 EXPECT_TRUE(pUrl.password.empty());
139 EXPECT_EQ(pUrl.domain, "domain");
140 EXPECT_EQ(*pUrl.port, 123); // NOLINT(bugprone-unchecked-optional-access)
141 EXPECT_EQ(pUrl.path, "/abc:321");
142 }
143
144 {
145 ParsedUrl pUrl;
146 EXPECT_TRUE(parseUrl(pUrl, "scheme://:pass@domain:123/abc:321"));
147 EXPECT_EQ(pUrl.scheme, "scheme");
148 EXPECT_TRUE(pUrl.username.empty());
149 EXPECT_EQ(pUrl.password, "pass");
150 EXPECT_EQ(pUrl.domain, "domain");
151 EXPECT_EQ(*pUrl.port, 123); // NOLINT(bugprone-unchecked-optional-access)
152 EXPECT_EQ(pUrl.path, "/abc:321");
153 }
154
155 {
156 ParsedUrl pUrl;
157 EXPECT_TRUE(parseUrl(pUrl, "scheme://domain:123/abc:321"));
158 EXPECT_EQ(pUrl.scheme, "scheme");
159 EXPECT_TRUE(pUrl.username.empty());
160 EXPECT_TRUE(pUrl.password.empty());
161 EXPECT_EQ(pUrl.domain, "domain");
162 EXPECT_EQ(*pUrl.port, 123); // NOLINT(bugprone-unchecked-optional-access)
163 EXPECT_EQ(pUrl.path, "/abc:321");
164 }
165
166 {
167 ParsedUrl pUrl;
168 EXPECT_TRUE(parseUrl(pUrl, "scheme://user:pass@domain/abc:321"));
169 EXPECT_EQ(pUrl.scheme, "scheme");
170 EXPECT_EQ(pUrl.username, "user");
171 EXPECT_EQ(pUrl.password, "pass");
172 EXPECT_EQ(pUrl.domain, "domain");
173 EXPECT_FALSE(pUrl.port);
174 EXPECT_EQ(pUrl.path, "/abc:321");
175 }
176
177 {
178 ParsedUrl pUrl;
179 EXPECT_TRUE(parseUrl(pUrl, "scheme://user@domain/abc:321"));
180 EXPECT_EQ(pUrl.scheme, "scheme");
181 EXPECT_EQ(pUrl.username, "user");
182 EXPECT_TRUE(pUrl.password.empty());
183 EXPECT_EQ(pUrl.domain, "domain");
184 EXPECT_FALSE(pUrl.port);
185 EXPECT_EQ(pUrl.path, "/abc:321");
186 }
187
188 {
189 ParsedUrl pUrl;
190 EXPECT_TRUE(parseUrl(pUrl, "scheme://:pass@domain/abc:321"));
191 EXPECT_EQ(pUrl.scheme, "scheme");
192 EXPECT_TRUE(pUrl.username.empty());
193 EXPECT_EQ(pUrl.password, "pass");
194 EXPECT_EQ(pUrl.domain, "domain");
195 EXPECT_FALSE(pUrl.port);
196 EXPECT_EQ(pUrl.path, "/abc:321");
197 }
198
199 {
200 ParsedUrl pUrl;
201 EXPECT_TRUE(parseUrl(pUrl, "scheme://domain/abc:321"));
202 EXPECT_EQ(pUrl.scheme, "scheme");
203 EXPECT_TRUE(pUrl.username.empty());
204 EXPECT_TRUE(pUrl.password.empty());
205 EXPECT_EQ(pUrl.domain, "domain");
206 EXPECT_FALSE(pUrl.port);
207 EXPECT_EQ(pUrl.path, "/abc:321");
208 }
209
210 {
211 ParsedUrl pUrl;
212 EXPECT_TRUE(parseUrl(pUrl, "scheme:///path/to/file"));
213 EXPECT_EQ(pUrl.scheme, "scheme");
214 EXPECT_TRUE(pUrl.username.empty());
215 EXPECT_TRUE(pUrl.password.empty());
216 EXPECT_TRUE(pUrl.domain.empty());
217 EXPECT_FALSE(pUrl.port);
218 EXPECT_EQ(pUrl.path, "/path/to/file");
219 }
220
221 {
222 ParsedUrl pUrl;
223 EXPECT_TRUE(parseUrl(pUrl, "scheme://user:pass@domain/path/with/an@sign"));
224 EXPECT_EQ(pUrl.scheme, "scheme");
225 EXPECT_EQ(pUrl.username, "user");
226 EXPECT_EQ(pUrl.password, "pass");
227 EXPECT_EQ(pUrl.domain, "domain");
228 EXPECT_FALSE(pUrl.port);
229 EXPECT_EQ(pUrl.path, "/path/with/an@sign");
230 }
231
232 {
233 ParsedUrl pUrl;
234 EXPECT_TRUE(parseUrl(pUrl, "scheme://domain/path/with/an@sign"));
235 EXPECT_EQ(pUrl.scheme, "scheme");
236 EXPECT_TRUE(pUrl.username.empty());
237 EXPECT_TRUE(pUrl.password.empty());
238 EXPECT_EQ(pUrl.domain, "domain");
239 EXPECT_FALSE(pUrl.port);
240 EXPECT_EQ(pUrl.path, "/path/with/an@sign");
241 }
242
243 {
244 ParsedUrl pUrl;
245 EXPECT_TRUE(parseUrl(pUrl, "scheme://:999/"));
246 EXPECT_EQ(pUrl.scheme, "scheme");
247 EXPECT_TRUE(pUrl.username.empty());
248 EXPECT_TRUE(pUrl.password.empty());
249 EXPECT_EQ(pUrl.domain, ":999");
250 EXPECT_FALSE(pUrl.port);
251 EXPECT_EQ(pUrl.path, "/");
252 }
253
254 {
255 ParsedUrl pUrl;
256 EXPECT_TRUE(parseUrl(pUrl, "http://::1:1234/validators"));
257 EXPECT_EQ(pUrl.scheme, "http");
258 EXPECT_TRUE(pUrl.username.empty());
259 EXPECT_TRUE(pUrl.password.empty());
260 EXPECT_EQ(pUrl.domain, "::0.1.18.52");
261 EXPECT_FALSE(pUrl.port);
262 EXPECT_EQ(pUrl.path, "/validators");
263 }
264
265 // Expected fails.
266 {
267 ParsedUrl pUrl;
268 EXPECT_FALSE(parseUrl(pUrl, ""));
269 EXPECT_FALSE(parseUrl(pUrl, "nonsense"));
270 EXPECT_FALSE(parseUrl(pUrl, "://"));
271 EXPECT_FALSE(parseUrl(pUrl, ":///"));
272 EXPECT_FALSE(parseUrl(pUrl, "scheme://user:pass@domain:65536/abc:321"));
273 EXPECT_FALSE(parseUrl(pUrl, "UPPER://domain:23498765/"));
274 EXPECT_FALSE(parseUrl(pUrl, "UPPER://domain:0/"));
275 EXPECT_FALSE(parseUrl(pUrl, "UPPER://domain:+7/"));
276 EXPECT_FALSE(parseUrl(pUrl, "UPPER://domain:-7234/"));
277 EXPECT_FALSE(parseUrl(pUrl, "UPPER://domain:@#$56!/"));
278 }
279
280 {
281 std::string const strUrl("s://" + std::string(8192, ':'));
282 ParsedUrl pUrl;
283 EXPECT_FALSE(parseUrl(pUrl, strUrl));
284 }
285}
286
288{
289 auto result = to_string("hello");
290 EXPECT_EQ(result, "hello");
291}
292
294{
295 EXPECT_EQ(trimWhitespace(""), "");
296 EXPECT_EQ(trimWhitespace(" "), "");
297 EXPECT_EQ(trimWhitespace("abc"), "abc");
298 EXPECT_EQ(trimWhitespace(" abc"), "abc");
299 EXPECT_EQ(trimWhitespace("abc "), "abc");
300 EXPECT_EQ(trimWhitespace(" \t\n\v\f\r abc \t\n\v\f\r "), "abc");
301
302 // Interior whitespace is preserved.
303 EXPECT_EQ(trimWhitespace(" a b\tc "), "a b\tc");
304}
305
307{
308 EXPECT_EQ(toLower(""), "");
309 EXPECT_EQ(toLower("ABC"), "abc");
310 EXPECT_EQ(toLower("AbC123"), "abc123");
311 EXPECT_EQ(toLower("already lower"), "already lower");
312
313 // Only 'A'-'Z' are remapped. Neighbouring punctuation and digits, which a
314 // buggy range check could catch, must survive untouched.
315 EXPECT_EQ(toLower("@[`{_^"), "@[`{_^");
316}
317
318// Both helpers are documented as depending only on their input. Guard that by
319// checking the bytes just outside ASCII, which a locale-aware isspace/tolower
320// could classify differently.
321TEST_F(StringUtilitiesTest, trimAndLowerIgnoreLocale)
322{
323 // 0xA0 is NO-BREAK SPACE in Latin-1 and is whitespace to some locales.
324 std::string const nbsp("\xA0", 1);
325 EXPECT_EQ(trimWhitespace(nbsp), nbsp);
326 EXPECT_EQ(trimWhitespace(" " + nbsp + " "), nbsp);
327
328 // 0xC0 is LATIN CAPITAL LETTER A WITH GRAVE in Latin-1.
329 std::string const agrave("\xC0", 1);
330 EXPECT_EQ(toLower(agrave), agrave);
331}
332
333} // namespace xrpl
static void testUnHexFailure(std::string const &strIn)
static void testUnHexSuccess(std::string const &strIn, std::string const &strExpected)
T empty(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string toLower(std::string str)
Fold ASCII upper case letters to lower case.
TEST_F(HardenedHashTest, user_types)
std::string trimWhitespace(std::string str)
Remove leading and trailing ASCII whitespace.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
Slice makeSlice(std::array< T, N > const &a)
Definition Slice.h:228
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
bool parseUrl(ParsedUrl &pUrl, std::string const &strUrl)
std::optional< std::uint16_t > port
std::string password
std::string username