blob: 4afed3f00f0e7a52af3a4f443a17f98360d6c811 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "rtc_base/string_encode.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Jonas Olsson6b1985d2018-07-05 11:59:48 +020015#include <sstream> // no-presubmit-check TODO(webrtc:8982)
16
Ali Tofighfd6a4d62022-03-31 10:36:48 +020017#include "api/array_view.h"
Yves Gerey3e707812018-11-28 16:47:49 +010018#include "test/gtest.h"
19
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000020namespace rtc {
21
Mirko Bonadei6a489f22019-04-09 15:11:12 +020022class HexEncodeTest : public ::testing::Test {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023 public:
Niels Möllere7e36012019-05-23 12:10:26 +020024 HexEncodeTest() : dec_res_(0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025 for (size_t i = 0; i < sizeof(data_); ++i) {
26 data_[i] = (i + 128) & 0xff;
27 }
28 memset(decoded_, 0x7f, sizeof(decoded_));
29 }
30
31 char data_[10];
Ali Tofighfd6a4d62022-03-31 10:36:48 +020032 absl::string_view data_view_{data_, sizeof(data_)};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000033 char decoded_[11];
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000034 size_t dec_res_;
35};
36
37// Test that we can convert to/from hex with no delimiter.
38TEST_F(HexEncodeTest, TestWithNoDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020039 std::string encoded = hex_encode(data_view_);
Niels Möllere7e36012019-05-23 12:10:26 +020040 EXPECT_EQ("80818283848586878889", encoded);
Ali Tofighfd6a4d62022-03-31 10:36:48 +020041 dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000042 ASSERT_EQ(sizeof(data_), dec_res_);
43 ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_));
44}
45
46// Test that we can convert to/from hex with a colon delimiter.
47TEST_F(HexEncodeTest, TestWithDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020048 std::string encoded = hex_encode_with_delimiter(data_view_, ':');
Niels Möllere7e36012019-05-23 12:10:26 +020049 EXPECT_EQ("80:81:82:83:84:85:86:87:88:89", encoded);
Ali Tofighfd6a4d62022-03-31 10:36:48 +020050 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':');
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000051 ASSERT_EQ(sizeof(data_), dec_res_);
52 ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_));
53}
54
55// Test that encoding with one delimiter and decoding with another fails.
56TEST_F(HexEncodeTest, TestWithWrongDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020057 std::string encoded = hex_encode_with_delimiter(data_view_, ':');
58 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, '/');
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059 ASSERT_EQ(0U, dec_res_);
60}
61
62// Test that encoding without a delimiter and decoding with one fails.
63TEST_F(HexEncodeTest, TestExpectedDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020064 std::string encoded = hex_encode(data_view_);
Niels Möllere7e36012019-05-23 12:10:26 +020065 EXPECT_EQ(sizeof(data_) * 2, encoded.size());
Ali Tofighfd6a4d62022-03-31 10:36:48 +020066 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':');
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000067 ASSERT_EQ(0U, dec_res_);
68}
69
70// Test that encoding with a delimiter and decoding without one fails.
71TEST_F(HexEncodeTest, TestExpectedNoDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020072 std::string encoded = hex_encode_with_delimiter(data_view_, ':');
Niels Möllere7e36012019-05-23 12:10:26 +020073 EXPECT_EQ(sizeof(data_) * 3 - 1, encoded.size());
Ali Tofighfd6a4d62022-03-31 10:36:48 +020074 dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000075 ASSERT_EQ(0U, dec_res_);
76}
77
78// Test that we handle a zero-length buffer with no delimiter.
79TEST_F(HexEncodeTest, TestZeroLengthNoDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020080 std::string encoded = hex_encode("");
Niels Möllere7e36012019-05-23 12:10:26 +020081 EXPECT_TRUE(encoded.empty());
Ali Tofighfd6a4d62022-03-31 10:36:48 +020082 dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083 ASSERT_EQ(0U, dec_res_);
84}
85
86// Test that we handle a zero-length buffer with a delimiter.
87TEST_F(HexEncodeTest, TestZeroLengthWithDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020088 std::string encoded = hex_encode_with_delimiter("", ':');
Niels Möllere7e36012019-05-23 12:10:26 +020089 EXPECT_TRUE(encoded.empty());
Ali Tofighfd6a4d62022-03-31 10:36:48 +020090 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':');
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091 ASSERT_EQ(0U, dec_res_);
92}
93
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094// Test that decoding into a too-small output buffer fails.
95TEST_F(HexEncodeTest, TestDecodeTooShort) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020096 dec_res_ =
97 hex_decode_with_delimiter(ArrayView<char>(decoded_, 4), "0123456789", 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000098 ASSERT_EQ(0U, dec_res_);
99 ASSERT_EQ(0x7f, decoded_[4]);
100}
101
102// Test that decoding non-hex data fails.
103TEST_F(HexEncodeTest, TestDecodeBogusData) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200104 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), "axyz", 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000105 ASSERT_EQ(0U, dec_res_);
106}
107
108// Test that decoding an odd number of hex characters fails.
109TEST_F(HexEncodeTest, TestDecodeOddHexDigits) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200110 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), "012", 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111 ASSERT_EQ(0U, dec_res_);
112}
113
114// Test that decoding a string with too many delimiters fails.
115TEST_F(HexEncodeTest, TestDecodeWithDelimiterTooManyDelimiters) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200116 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4),
117 "01::23::45::67", ':');
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000118 ASSERT_EQ(0U, dec_res_);
119}
120
121// Test that decoding a string with a leading delimiter fails.
122TEST_F(HexEncodeTest, TestDecodeWithDelimiterLeadingDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200123 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4),
124 ":01:23:45:67", ':');
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000125 ASSERT_EQ(0U, dec_res_);
126}
127
128// Test that decoding a string with a trailing delimiter fails.
129TEST_F(HexEncodeTest, TestDecodeWithDelimiterTrailingDelimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200130 dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4),
131 "01:23:45:67:", ':');
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000132 ASSERT_EQ(0U, dec_res_);
133}
134
135// Tests counting substrings.
136TEST(TokenizeTest, CountSubstrings) {
137 std::vector<std::string> fields;
138
139 EXPECT_EQ(5ul, tokenize("one two three four five", ' ', &fields));
140 fields.clear();
141 EXPECT_EQ(1ul, tokenize("one", ' ', &fields));
142
143 // Extra spaces should be ignored.
144 fields.clear();
145 EXPECT_EQ(5ul, tokenize(" one two three four five ", ' ', &fields));
146 fields.clear();
147 EXPECT_EQ(1ul, tokenize(" one ", ' ', &fields));
148 fields.clear();
149 EXPECT_EQ(0ul, tokenize(" ", ' ', &fields));
150}
151
152// Tests comparing substrings.
153TEST(TokenizeTest, CompareSubstrings) {
154 std::vector<std::string> fields;
155
156 tokenize("find middle one", ' ', &fields);
157 ASSERT_EQ(3ul, fields.size());
158 ASSERT_STREQ("middle", fields.at(1).c_str());
159 fields.clear();
160
161 // Extra spaces should be ignored.
162 tokenize(" find middle one ", ' ', &fields);
163 ASSERT_EQ(3ul, fields.size());
164 ASSERT_STREQ("middle", fields.at(1).c_str());
165 fields.clear();
166 tokenize(" ", ' ', &fields);
167 ASSERT_EQ(0ul, fields.size());
168}
169
Donald Curtis0e07f922015-05-15 09:21:23 -0700170TEST(TokenizeFirstTest, NoLeadingSpaces) {
171 std::string token;
172 std::string rest;
173
174 ASSERT_TRUE(tokenize_first("A &*${}", ' ', &token, &rest));
175 ASSERT_STREQ("A", token.c_str());
176 ASSERT_STREQ("&*${}", rest.c_str());
177
178 ASSERT_TRUE(tokenize_first("A B& *${}", ' ', &token, &rest));
179 ASSERT_STREQ("A", token.c_str());
180 ASSERT_STREQ("B& *${}", rest.c_str());
181
182 ASSERT_TRUE(tokenize_first("A B& *${} ", ' ', &token, &rest));
183 ASSERT_STREQ("A", token.c_str());
184 ASSERT_STREQ("B& *${} ", rest.c_str());
185}
186
187TEST(TokenizeFirstTest, LeadingSpaces) {
188 std::string token;
189 std::string rest;
190
191 ASSERT_TRUE(tokenize_first(" A B C", ' ', &token, &rest));
192 ASSERT_STREQ("", token.c_str());
193 ASSERT_STREQ("A B C", rest.c_str());
194
195 ASSERT_TRUE(tokenize_first(" A B C ", ' ', &token, &rest));
196 ASSERT_STREQ("", token.c_str());
197 ASSERT_STREQ("A B C ", rest.c_str());
198}
199
200TEST(TokenizeFirstTest, SingleToken) {
201 std::string token;
202 std::string rest;
203
204 // In the case where we cannot find delimiter the whole string is a token.
205 ASSERT_FALSE(tokenize_first("ABC", ' ', &token, &rest));
206
207 ASSERT_TRUE(tokenize_first("ABC ", ' ', &token, &rest));
208 ASSERT_STREQ("ABC", token.c_str());
209 ASSERT_STREQ("", rest.c_str());
210
211 ASSERT_TRUE(tokenize_first(" ABC ", ' ', &token, &rest));
212 ASSERT_STREQ("", token.c_str());
213 ASSERT_STREQ("ABC ", rest.c_str());
214}
215
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000216// Tests counting substrings.
217TEST(SplitTest, CountSubstrings) {
218 std::vector<std::string> fields;
219
220 EXPECT_EQ(5ul, split("one,two,three,four,five", ',', &fields));
221 fields.clear();
222 EXPECT_EQ(1ul, split("one", ',', &fields));
223
224 // Empty fields between commas count.
225 fields.clear();
226 EXPECT_EQ(5ul, split("one,,three,four,five", ',', &fields));
227 fields.clear();
228 EXPECT_EQ(3ul, split(",three,", ',', &fields));
229 fields.clear();
230 EXPECT_EQ(1ul, split("", ',', &fields));
231}
232
233// Tests comparing substrings.
234TEST(SplitTest, CompareSubstrings) {
235 std::vector<std::string> fields;
236
237 split("find,middle,one", ',', &fields);
238 ASSERT_EQ(3ul, fields.size());
239 ASSERT_STREQ("middle", fields.at(1).c_str());
240 fields.clear();
241
242 // Empty fields between commas count.
243 split("find,,middle,one", ',', &fields);
244 ASSERT_EQ(4ul, fields.size());
245 ASSERT_STREQ("middle", fields.at(2).c_str());
246 fields.clear();
247 split("", ',', &fields);
248 ASSERT_EQ(1ul, fields.size());
249 ASSERT_STREQ("", fields.at(0).c_str());
250}
251
Niels Möller634f2792021-09-07 16:06:57 +0200252TEST(SplitTest, EmptyTokens) {
253 std::vector<std::string> fields;
254 EXPECT_EQ(3ul, split("a.b.c", '.', &fields));
255 EXPECT_EQ("a", fields[0]);
256 EXPECT_EQ("b", fields[1]);
257 EXPECT_EQ("c", fields[2]);
258
259 EXPECT_EQ(3ul, split("..c", '.', &fields));
260 EXPECT_TRUE(fields[0].empty());
261 EXPECT_TRUE(fields[1].empty());
262 EXPECT_EQ("c", fields[2]);
263
264 EXPECT_EQ(1ul, split("", '.', &fields));
265 EXPECT_TRUE(fields[0].empty());
266}
267
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200268TEST(ToString, SanityCheck) {
269 EXPECT_EQ(ToString(true), "true");
270 EXPECT_EQ(ToString(false), "false");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000271
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200272 const char* c = "message";
273 EXPECT_EQ(ToString(c), c);
274 EXPECT_EQ(ToString(std::string(c)), c);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000275
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200276 EXPECT_EQ(ToString(short{-123}), "-123");
277 EXPECT_EQ(ToString((unsigned short)123), "123");
278 EXPECT_EQ(ToString(int{-123}), "-123");
279 EXPECT_EQ(ToString((unsigned int)123), "123");
280 EXPECT_EQ(ToString((long int)-123), "-123");
281 EXPECT_EQ(ToString((unsigned long int)123), "123");
282 EXPECT_EQ(ToString((long long int)-123), "-123");
283 EXPECT_EQ(ToString((unsigned long long int)123), "123");
284
285 int i = 10;
286 int* p = &i;
287 std::ostringstream s; // no-presubmit-check TODO(webrtc:8982)
288 s << p;
289 EXPECT_EQ(s.str(), ToString(p));
290
291 EXPECT_EQ(ToString(0.5), "0.5");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000292}
293
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200294template <typename T>
295void ParsesTo(std::string s, T t) {
296 T value;
297 EXPECT_TRUE(FromString(s, &value));
298 EXPECT_EQ(value, t);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000299}
300
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200301TEST(FromString, DecodeValid) {
302 ParsesTo("true", true);
303 ParsesTo("false", false);
304
305 ParsesTo("105", 105);
306 ParsesTo("0.25", 0.25);
307}
308
309template <typename T>
310void FailsToParse(std::string s) {
311 T value;
312 EXPECT_FALSE(FromString(s, &value)) << "[" << s << "]";
313}
314
315TEST(FromString, DecodeInvalid) {
316 FailsToParse<bool>("True");
317 FailsToParse<bool>("0");
318 FailsToParse<bool>("yes");
319
320 FailsToParse<int>("0.5");
321 FailsToParse<int>("XIV");
322 FailsToParse<double>("");
323 FailsToParse<double>(" ");
324 FailsToParse<int>("1 2");
325}
326
327template <typename T>
328void RoundTrip(T t) {
329 std::string s = ToString(t);
330 T value;
331 EXPECT_TRUE(FromString(s, &value));
332 EXPECT_EQ(value, t);
333}
334
335TEST(FromString, RoundTrip) {
336 RoundTrip<int>(123);
337 RoundTrip(false);
338 RoundTrip(true);
339 RoundTrip(0.5);
340 RoundTrip(-15l);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341}
deadbeef0a6c4ca2015-10-06 11:38:28 -0700342
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000343} // namespace rtc