1 /*
2  * Copyright (C) 2004-2020 ZNC, see the NOTICE file for details.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 #include <znc/ZNCString.h>
19 
20 class EscapeTest : public ::testing::Test {
21   protected:
testEncode(const CString & in,const CString & expectedOut,const CString & sformat)22     void testEncode(const CString& in, const CString& expectedOut,
23                     const CString& sformat) {
24         CString::EEscape format = CString::ToEscape(sformat);
25         CString out;
26 
27         SCOPED_TRACE("Format: " + sformat);
28 
29         // Encode, then decode again and check we still got the same string
30         out = in.Escape_n(CString::EASCII, format);
31         EXPECT_EQ(out, expectedOut);
32         out = out.Escape_n(format, CString::EASCII);
33         EXPECT_EQ(out, in);
34     }
35 
testString(const CString & in,const CString & url,const CString & html,const CString & sql,const CString & tag)36     void testString(const CString& in, const CString& url, const CString& html,
37                     const CString& sql, const CString& tag) {
38         SCOPED_TRACE("String: " + in);
39 
40         testEncode(in, url, "URL");
41         testEncode(in, html, "HTML");
42         testEncode(in, sql, "SQL");
43         testEncode(in, tag, "MSGTAG");
44     }
45 };
46 
TEST_F(EscapeTest,Test)47 TEST_F(EscapeTest, Test) {
48     // clang-format off
49     //          input     url          html             sql         msgtag
50     testString("abcdefg","abcdefg",   "abcdefg",       "abcdefg",   "abcdefg");
51     testString("\n\t\r", "%0A%09%0D", "\n\t\r",        "\\n\\t\\r", "\\n\t\\r");
52     testString("'\"",    "%27%22",    "'&quot;",       "\\'\\\"",   "'\"");
53     testString("&<>",    "%26%3C%3E", "&amp;&lt;&gt;", "&<>",       "&<>");
54     testString(" ;",     "+%3B",      " ;",            " ;",        "\\s\\:");
55     // clang-format on
56     EXPECT_EQ(CString("a&lt.b&gt;c").Escape_n(CString::EHTML, CString::EASCII),
57               "a&lt.b>c");
58 }
59 
TEST(StringTest,Bool)60 TEST(StringTest, Bool) {
61     EXPECT_TRUE(CString(true).ToBool());
62     EXPECT_FALSE(CString(false).ToBool());
63 }
64 
65 #define CS(s) (CString((s), sizeof(s) - 1))
66 
TEST(StringTest,Cmp)67 TEST(StringTest, Cmp) {
68     CString s = "Bbb";
69 
70     EXPECT_EQ(s, CString("Bbb"));
71     EXPECT_LT(CString("Aaa"), s);
72     EXPECT_GT(CString("Ccc"), s);
73     EXPECT_EQ(s.StrCmp("Bbb"), 0);
74     EXPECT_GT(0, s.StrCmp("bbb"));
75     EXPECT_LT(0, s.StrCmp("Aaa"));
76     EXPECT_GT(0, s.StrCmp("Ccc"));
77     EXPECT_EQ(s.CaseCmp("Bbb"), 0);
78     EXPECT_EQ(s.CaseCmp("bbb"), 0);
79     EXPECT_LT(0, s.CaseCmp("Aaa"));
80     EXPECT_GT(0, s.CaseCmp("Ccc"));
81 
82     EXPECT_TRUE(s.Equals("bbb"));
83     EXPECT_FALSE(s.Equals("bbb", true));
84     EXPECT_FALSE(s.Equals("bb"));
85 }
86 
TEST(StringTest,Wild)87 TEST(StringTest, Wild) {
88     EXPECT_TRUE(CString::WildCmp("", "", CString::CaseSensitive));
89     EXPECT_TRUE(CString::WildCmp("", "", CString::CaseInsensitive));
90 
91     EXPECT_FALSE(CString::WildCmp("*a*b*c*", "xy", CString::CaseSensitive));
92     EXPECT_FALSE(CString::WildCmp("*a*b*c*", "xy", CString::CaseInsensitive));
93 
94     EXPECT_TRUE(CString::WildCmp("*!?bar@foo", "I_am!~bar@foo",
95                                  CString::CaseSensitive));
96     EXPECT_TRUE(CString::WildCmp("*!?bar@foo", "I_am!~bar@foo",
97                                  CString::CaseInsensitive));
98 
99     EXPECT_FALSE(CString::WildCmp("*!?BAR@foo", "I_am!~bar@foo",
100                                   CString::CaseSensitive));
101     EXPECT_TRUE(CString::WildCmp("*!?BAR@foo", "I_am!~bar@foo",
102                                  CString::CaseInsensitive));
103 
104     EXPECT_TRUE(CString::WildCmp("*a*b*c*", "abc", CString::CaseSensitive));
105     EXPECT_TRUE(CString::WildCmp("*a*b*c*", "abc", CString::CaseInsensitive));
106 
107     EXPECT_FALSE(CString::WildCmp("*A*b*c*", "abc", CString::CaseSensitive));
108     EXPECT_TRUE(CString::WildCmp("*A*b*c*", "abc", CString::CaseInsensitive));
109 
110     EXPECT_FALSE(CString::WildCmp("*a*b*c*", "Abc", CString::CaseSensitive));
111     EXPECT_TRUE(CString::WildCmp("*a*b*c*", "Abc", CString::CaseInsensitive));
112 
113     EXPECT_TRUE(CString::WildCmp("*a*b*c*", "axbyc", CString::CaseSensitive));
114     EXPECT_TRUE(CString::WildCmp("*a*b*c*", "axbyc", CString::CaseInsensitive));
115 
116     EXPECT_FALSE(CString::WildCmp("*a*B*c*", "AxByC", CString::CaseSensitive));
117     EXPECT_TRUE(CString::WildCmp("*a*B*c*", "AxByC", CString::CaseInsensitive));
118 }
119 
TEST(StringTest,Case)120 TEST(StringTest, Case) {
121     CString x = CS("xx");
122     CString X = CS("XX");
123     EXPECT_EQ(x.AsUpper(), X);
124     EXPECT_EQ(X.AsLower(), x);
125 }
126 
TEST(StringTest,Replace)127 TEST(StringTest, Replace) {
128     EXPECT_EQ(CString("(a()a)").Replace_n("a", "b"), "(b()b)");
129     EXPECT_EQ(CString("(a()a)").Replace_n("a", "b", "(", ")"), "(a()b)");
130     EXPECT_EQ(CString("(a()a)").Replace_n("a", "b", "(", ")", true), "a(b)");
131 }
132 
TEST(StringTest,Misc)133 TEST(StringTest, Misc) {
134     EXPECT_EQ(CString("Hello, I'm Bob").Ellipsize(9), "Hello,...");
135     EXPECT_EQ(CString("Hello, I'm Bob").Ellipsize(90), "Hello, I'm Bob");
136     EXPECT_EQ(CString("Hello, I'm Bob").Ellipsize(2), "..");
137 
138     EXPECT_EQ(CS("Xyz").Left(2), "Xy");
139     EXPECT_EQ(CS("Xyz").Left(20), "Xyz");
140 
141     EXPECT_EQ(CS("Xyz").Right(2), "yz");
142     EXPECT_EQ(CS("Xyz").Right(20), "Xyz");
143 }
144 
TEST(StringTest,Split)145 TEST(StringTest, Split) {
146     EXPECT_EQ(CS("a b c").Token(0), "a");
147     EXPECT_EQ(CS("a b c").Token(1), "b");
148     EXPECT_EQ(CS("a b c").Token(100), "");
149     EXPECT_EQ(CS("a b c").Token(1, true), "b c");
150     EXPECT_EQ(CS("a  c").Token(1), "c");
151     EXPECT_EQ(CS("a  c").Token(1, false, " ", true), "");
152     EXPECT_EQ(CS("a  c").Token(1, false, "  "), "c");
153     EXPECT_EQ(CS("a   c").Token(1, false, "  "), " c");
154     EXPECT_EQ(CS("a    c").Token(1, false, "  "), "c");
155     EXPECT_EQ(CS("a (b c) d").Token(1, false, " ", false, "(", ")"), "b c");
156     EXPECT_EQ(CS("a (b c) d").Token(1, false, " ", false, "(", ")", false),
157               "(b c)");
158     EXPECT_EQ(CS("a (b c) d").Token(2, false, " ", false, "(", ")", false),
159               "d");
160 
161     VCString vexpected;
162     VCString vresult;
163 
164     vexpected.push_back("a");
165     vexpected.push_back("b");
166     vexpected.push_back("c");
167     CS("a b c").Split(" ", vresult);
168     EXPECT_EQ(vresult, vexpected);
169 
170     MCString mexpected = {{"a", "b"}, {"c", "d"}};
171     MCString mresult;
172 
173     CS("a=x&c=d&a=b").URLSplit(mresult);
174     EXPECT_EQ(mexpected, mresult) << "URLSplit";
175 }
176 
TEST(StringTest,NamedFormat)177 TEST(StringTest, NamedFormat) {
178     MCString m = {{"a", "b"}};
179     EXPECT_EQ(CString::NamedFormat(CS("\\{x{a}y{a}"), m), "{xbyb");
180 }
181 
TEST(StringTest,Hash)182 TEST(StringTest, Hash) {
183     EXPECT_EQ(CS("").MD5(), "d41d8cd98f00b204e9800998ecf8427e");
184     EXPECT_EQ(CS("a").MD5(), "0cc175b9c0f1b6a831c399e269772661");
185 
186     EXPECT_EQ(
187         CS("").SHA256(),
188         "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
189     EXPECT_EQ(
190         CS("a").SHA256(),
191         "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb");
192 }
193 
TEST(StringTest,Equals)194 TEST(StringTest, Equals) {
195     EXPECT_TRUE(CS("ABC").Equals("abc"));
196     EXPECT_TRUE(CS("ABC").Equals("abc", CString::CaseInsensitive));
197     EXPECT_FALSE(CS("ABC").Equals("abc", CString::CaseSensitive));
198     EXPECT_TRUE(CS("ABC").Equals("abc", false));  // deprecated
199     EXPECT_FALSE(CS("ABC").Equals("abc", true));  // deprecated
200 }
201 
TEST(StringTest,Find)202 TEST(StringTest, Find) {
203     EXPECT_EQ(CString("Hello, I'm Bob").Find("Hello"), 0u);
204     EXPECT_EQ(CString("Hello, I'm Bob").Find("Hello", CString::CaseInsensitive),
205               0u);
206     EXPECT_EQ(CString("Hello, I'm Bob").Find("Hello", CString::CaseSensitive),
207               0u);
208 
209     EXPECT_EQ(CString("Hello, I'm Bob").Find("i'm"), 7u);
210     EXPECT_EQ(CString("Hello, I'm Bob").Find("i'm", CString::CaseInsensitive),
211               7u);
212     EXPECT_EQ(CString("Hello, I'm Bob").Find("i'm", CString::CaseSensitive),
213               CString::npos);
214 }
215 
TEST(StringTest,StartsWith)216 TEST(StringTest, StartsWith) {
217     EXPECT_TRUE(CString("Hello, I'm Bob").StartsWith("Hello"));
218     EXPECT_TRUE(CString("Hello, I'm Bob")
219                     .StartsWith("Hello", CString::CaseInsensitive));
220     EXPECT_TRUE(
221         CString("Hello, I'm Bob").StartsWith("Hello", CString::CaseSensitive));
222 
223     EXPECT_TRUE(CString("Hello, I'm Bob").StartsWith("hello"));
224     EXPECT_TRUE(CString("Hello, I'm Bob")
225                     .StartsWith("hello", CString::CaseInsensitive));
226     EXPECT_FALSE(
227         CString("Hello, I'm Bob").StartsWith("hello", CString::CaseSensitive));
228 }
229 
TEST(StringTest,EndsWith)230 TEST(StringTest, EndsWith) {
231     EXPECT_TRUE(CString("Hello, I'm Bob").EndsWith("Bob"));
232     EXPECT_TRUE(
233         CString("Hello, I'm Bob").EndsWith("Bob", CString::CaseInsensitive));
234     EXPECT_TRUE(
235         CString("Hello, I'm Bob").EndsWith("Bob", CString::CaseSensitive));
236 
237     EXPECT_TRUE(CString("Hello, I'm Bob").EndsWith("bob"));
238     EXPECT_TRUE(
239         CString("Hello, I'm Bob").EndsWith("bob", CString::CaseInsensitive));
240     EXPECT_FALSE(
241         CString("Hello, I'm Bob").EndsWith("bob", CString::CaseSensitive));
242 }
243 
TEST(StringTest,Contains)244 TEST(StringTest, Contains) {
245     EXPECT_TRUE(CString("Hello, I'm Bob").Contains("Hello"));
246     EXPECT_TRUE(
247         CString("Hello, I'm Bob").Contains("Hello", CString::CaseInsensitive));
248     EXPECT_TRUE(
249         CString("Hello, I'm Bob").Contains("Hello", CString::CaseSensitive));
250 
251     EXPECT_TRUE(CString("Hello, I'm Bob").Contains("i'm"));
252     EXPECT_TRUE(
253         CString("Hello, I'm Bob").Contains("i'm", CString::CaseInsensitive));
254     EXPECT_FALSE(
255         CString("Hello, I'm Bob").Contains("i'm", CString::CaseSensitive));
256 
257     EXPECT_TRUE(CString("Hello, I'm Bob").Contains("i'm bob"));
258     EXPECT_TRUE(CString("Hello, I'm Bob")
259                     .Contains("i'm bob", CString::CaseInsensitive));
260     EXPECT_FALSE(
261         CString("Hello, I'm Bob").Contains("i'm bob", CString::CaseSensitive));
262 }
263 
TEST(StringTest,StripControls)264 TEST(StringTest, StripControls) {
265     // Strips reset colours
266     EXPECT_EQ(CString("\x03test").StripControls(), "test");
267 
268     // Strips reset foreground and set new background colour
269     EXPECT_EQ(CString("\x03,03test").StripControls(), "test");
270 
271     // Strips foreground and background colour
272     EXPECT_EQ(CString("\x03\x30,03test").StripControls(), "test");
273 
274     // Strips reset
275     EXPECT_EQ(CString("\x0Ftest").StripControls(), "test");
276 
277     // Strips reverse
278     EXPECT_EQ(CString("\x12test").StripControls(), "test");
279 
280     // Strips bold
281     EXPECT_EQ(CString("\x02test").StripControls(), "test");
282 
283     // Strips italics
284     EXPECT_EQ(CString("\x16test").StripControls(), "test");
285 
286     // Strips underline
287     EXPECT_EQ(CString("\x1Ftest").StripControls(), "test");
288 }
289