xref: /aosp_15_r20/external/cronet/net/base/url_search_params_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/base/url_search_params.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/containers/flat_map.h"
11 #include "base/strings/string_util.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "url/gurl.h"
15 
16 namespace net {
17 namespace {
18 
19 using ::testing::ElementsAre;
20 using ::testing::Pair;
21 
TEST(UrlSearchParamsTest,ParseAllSearchParams)22 TEST(UrlSearchParamsTest, ParseAllSearchParams) {
23   const UrlSearchParams search_params(
24       GURL("https://a.test/index.html?a=1&b=2&c=3"));
25   EXPECT_THAT(search_params.params(),
26               ElementsAre(Pair("a", "1"), Pair("b", "2"), Pair("c", "3")));
27 }
28 
TEST(UrlSearchParamsTest,ParseSearchParamUnescapeValue)29 TEST(UrlSearchParamsTest, ParseSearchParamUnescapeValue) {
30   const UrlSearchParams search_params(
31       GURL(R"(https://a.test/index.html?a=a%20b%20c)"));
32   EXPECT_EQ(search_params.params().size(), 1u);
33   EXPECT_EQ(search_params.params()[0].second, "a b c");
34 }
35 
TEST(UrlSearchParamsTest,DeleteOneSearchParams)36 TEST(UrlSearchParamsTest, DeleteOneSearchParams) {
37   UrlSearchParams search_params(GURL("https://a.test/index.html?a=1&b=2&c=3"));
38   search_params.DeleteAllWithNames({"b"});
39   EXPECT_THAT(search_params.params(),
40               ElementsAre(Pair("a", "1"), Pair("c", "3")));
41 }
42 
TEST(UrlSearchParamsTest,DeleteAllExceptOneSearchParams)43 TEST(UrlSearchParamsTest, DeleteAllExceptOneSearchParams) {
44   UrlSearchParams search_params(GURL("https://a.test/index.html?a=1&b=2&c=3"));
45   search_params.DeleteAllExceptWithNames({"b"});
46   EXPECT_THAT(search_params.params(), ElementsAre(Pair("b", "2")));
47 }
48 
TEST(UrlSearchParamsTest,SortSearchParams)49 TEST(UrlSearchParamsTest, SortSearchParams) {
50   UrlSearchParams search_params(
51       GURL("https://a.test/index.html?c=3&b=2&a=1&c=2&a=5"));
52   search_params.Sort();
53   EXPECT_THAT(search_params.params(),
54               ElementsAre(Pair("a", "1"), Pair("a", "5"), Pair("b", "2"),
55                           Pair("c", "3"), Pair("c", "2")));
56 }
57 
TEST(UrlSearchParamsTest,SortSearchParamsPercentEncoded)58 TEST(UrlSearchParamsTest, SortSearchParamsPercentEncoded) {
59   UrlSearchParams search_params(
60       GURL("https://a.test/index.html?c=3&b=2&a=1&%63=2&a=5"));
61   search_params.Sort();
62   EXPECT_THAT(search_params.params(),
63               ElementsAre(Pair("a", "1"), Pair("a", "5"), Pair("b", "2"),
64                           Pair("c", "3"), Pair("c", "2")));
65 }
66 
TEST(UrlSearchParamsTest,ParseSearchParamsSpacePlusAndPercentEncoded)67 TEST(UrlSearchParamsTest, ParseSearchParamsSpacePlusAndPercentEncoded) {
68   const UrlSearchParams search_params(
69       GURL(R"(https://a.test/index.html?c+1=3&b+%202=2&a=1&%63%201=2&a=5)"));
70   EXPECT_THAT(search_params.params(),
71               ElementsAre(Pair("c 1", "3"), Pair("b  2", "2"), Pair("a", "1"),
72                           Pair("c 1", "2"), Pair("a", "5")));
73 }
74 
TEST(UrlSearchParamsTest,ParseSearchParamsDoubleCodePoint)75 TEST(UrlSearchParamsTest, ParseSearchParamsDoubleCodePoint) {
76   const UrlSearchParams search_params(
77       GURL(R"(https://a.test/index.html?%C3%A9=foo)"));
78   EXPECT_THAT(search_params.params(), ElementsAre(Pair("é", "foo")));
79 }
80 
TEST(UrlSearchParamsTest,SortSearchParamsDoubleCodePoint)81 TEST(UrlSearchParamsTest, SortSearchParamsDoubleCodePoint) {
82   UrlSearchParams search_params(
83       GURL(R"(https://a.test/index.html?%C3%A9=f&a=2&c=4&é=b)"));
84   search_params.Sort();
85   EXPECT_THAT(search_params.params(),
86               ElementsAre(Pair("a", "2"), Pair("c", "4"), Pair("é", "f"),
87                           Pair("é", "b")));
88 }
89 
TEST(UrlSearchParamsTest,ParseSearchParamsTripleCodePoint)90 TEST(UrlSearchParamsTest, ParseSearchParamsTripleCodePoint) {
91   const UrlSearchParams search_params(
92       GURL(R"(https://a.test/index.html?%E3%81%81=foo)"));
93   EXPECT_THAT(search_params.params(), ElementsAre(Pair("ぁ", "foo")));
94 }
95 
TEST(UrlSearchParamsTest,ParseSearchParamsQuadrupleCodePoint)96 TEST(UrlSearchParamsTest, ParseSearchParamsQuadrupleCodePoint) {
97   const UrlSearchParams search_params(
98       GURL(R"(https://a.test/index.html?%F0%90%A8%80=foo)"));
99   EXPECT_THAT(search_params.params(), ElementsAre(Pair("��", "foo")));
100 }
101 
102 // In case an invalid UTF-8 sequence is entered, it would be replaced with
103 // the U+FFFD REPLACEMENT CHARACTER: �.
TEST(UrlSearchParamsTest,ParseSearchParamsInvalidCodePoint)104 TEST(UrlSearchParamsTest, ParseSearchParamsInvalidCodePoint) {
105   const UrlSearchParams search_params(
106       GURL(R"(https://a.test/index.html?%C3=foo)"));
107   EXPECT_THAT(search_params.params(), ElementsAre(Pair("�", "foo")));
108 }
109 
TEST(UrlSearchParamsTest,ParseSearchParamsSpecialCharacters)110 TEST(UrlSearchParamsTest, ParseSearchParamsSpecialCharacters) {
111   // Use special characters in both `keys` and `values`.
112   const base::flat_map<std::string, std::string> percent_encoding = {
113       {"!", "%21"},    {R"(")", "%22"},  // double quote character: "
114       {"#", "%23"},    {"$", "%24"},       {"%", "%25"},    {"&", "%26"},
115       {"'", "%27"},    {"(", "%28"},       {")", "%29"},    {"*", R"(%2A)"},
116       {"+", R"(%2B)"}, {",", R"(%2C)"},    {"-", R"(%2D)"}, {".", R"(%2E)"},
117       {"/", R"(%2F)"}, {":", R"(%3A)"},    {";", "%3B"},    {"<", R"(%3C)"},
118       {"=", R"(%3D)"}, {">", R"(%3E)"},    {"?", R"(%3F)"}, {"@", "%40"},
119       {"[", "%5B"},    {R"(\)", R"(%5C)"}, {"]", R"(%5D)"}, {"^", R"(%5E)"},
120       {"_", R"(%5F)"}, {"`", "%60"},       {"{", "%7B"},    {"|", R"(%7C)"},
121       {"}", R"(%7D)"}, {"~", R"(%7E)"},    {"", ""},
122   };
123 
124   for (const auto& [key, value] : percent_encoding) {
125     std::string template_url = R"(https://a.test/index.html?$key=$value)";
126 
127     base::ReplaceSubstringsAfterOffset(&template_url, 0, "$key", value);
128     base::ReplaceSubstringsAfterOffset(&template_url, 0, "$value", value);
129 
130     const UrlSearchParams search_params = UrlSearchParams(GURL(template_url));
131     EXPECT_THAT(search_params.params(), ElementsAre(Pair(key, key)));
132   }
133 }
134 
135 TEST(UrlSearchParamsTest, ParseSearchParamsEmptyKeyOrValues) {
136   const UrlSearchParams search_params(
137       GURL("https://a.test/index.html?a&b&c&d&=5&=1"));
138   EXPECT_THAT(search_params.params(),
139               ElementsAre(Pair("a", ""), Pair("b", ""), Pair("c", ""),
140                           Pair("d", ""), Pair("", "5"), Pair("", "1")));
141 }
142 
143 TEST(UrlSearchParamsTest, ParseSearchParamsInvalidEscapeTest) {
144   const UrlSearchParams search_params(
145       GURL(R"(https://a.test/index.html?a=%3&%3=b)"));
146   EXPECT_THAT(search_params.params(),
147               ElementsAre(Pair("a", "%3"), Pair("%3", "b")));
148 }
149 
150 }  // namespace
151 }  // namespace net
152