• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2008-2010, Google Inc.
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Neither the name of Google Inc. nor the names of its
11  * contributors may be used to endorse or promote products derived from
12  * this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 // This file is part of ThreadSanitizer, a dynamic data race detector.
28 // Author: Evgeniy Stepanov.
29 
30 // This file contains tests for suppressions implementation.
31 
32 #include <gtest/gtest.h>
33 
34 #include "suppressions.h"
35 
36 #define VEC(arr) *(new vector<string>(arr, arr + sizeof(arr) / sizeof(*arr)))
37 
38 class BaseSuppressionsTest : public ::testing::Test {
39  protected:
IsSuppressed(string tool,string warning_type,const vector<string> & f_m,const vector<string> & f_d,const vector<string> & o)40   bool IsSuppressed(string tool, string warning_type, const vector<string>& f_m,
41       const vector<string>& f_d, const vector<string>& o) {
42     string result;
43     return supp_.StackTraceSuppressed(
44         tool, warning_type, f_m, f_d, o, &result);
45   }
46 
IsSuppressed(const vector<string> & f_m,const vector<string> & f_d,const vector<string> & o)47   bool IsSuppressed(const vector<string>& f_m, const vector<string>& f_d,
48       const vector<string>& o) {
49     return IsSuppressed("test_tool", "test_warning_type", f_m, f_d, o);
50   }
51 
52   Suppressions supp_;
53 };
54 
55 class SuppressionsTest : public BaseSuppressionsTest {
56  protected:
SetUp()57   virtual void SetUp() {
58     const string data =
59         "{\n"
60         "  name\n"
61         "  test_tool,tool2:test_warning_type\n"
62         "  fun:function1\n"
63         "  obj:object1\n"
64         "  fun:function2\n"
65         "}";
66     supp_.ReadFromString(data);
67   }
68 };
69 
70 
TEST_F(SuppressionsTest,Simple)71 TEST_F(SuppressionsTest, Simple) {
72   string m[] = {"aa", "bb", "cc"};
73   string d[] = {"aaa", "bbb", "ccc"};
74   string o[] = {"object1", "object2", "object3"};
75   ASSERT_FALSE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
76 }
77 
TEST_F(SuppressionsTest,Simple2)78 TEST_F(SuppressionsTest, Simple2) {
79   string m[] = {"function1", "bb", "function2"};
80   string d[] = {"aaa", "bbb", "ccc"};
81   string o[] = {"object2", "object1", "object3"};
82   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
83 }
84 
85 // A long stack trace is ok.
TEST_F(SuppressionsTest,LongTrace)86 TEST_F(SuppressionsTest, LongTrace) {
87   string m[] = {"function1", "bb", "function2", "zz"};
88   string d[] = {"aaa", "bbb", "ccc", "zzz"};
89   string o[] = {"object2", "object1", "object3", "o4"};
90   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
91 }
92 
93 // A stack trace template only matches at the top of the stack.
TEST_F(SuppressionsTest,OnlyMatchesAtTheTop)94 TEST_F(SuppressionsTest, OnlyMatchesAtTheTop) {
95   string m[] = {"zz", "function1", "bb", "function2"};
96   string d[] = {"zzz", "aaa", "bbb", "ccc"};
97   string o[] = {"o0", "object2", "object1", "object3"};
98   ASSERT_FALSE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
99 }
100 
101 // A short stack trace is not.
TEST_F(SuppressionsTest,ShortTrace)102 TEST_F(SuppressionsTest, ShortTrace) {
103   string m[] = {"function1", "bb"};
104   string d[] = {"aaa", "bbb"};
105   string o[] = {"object2", "object1"};
106   ASSERT_FALSE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
107 }
108 
109 class SuppressionsWithWildcardsTest : public BaseSuppressionsTest {
110  protected:
SetUp()111   virtual void SetUp() {
112     const string data =
113         "{\n"
114         "  name\n"
115         "  test_tool,tool2:test_warning_type\n"
116         "  fun:fun*1\n"
117         "  obj:obj*t1\n"
118         "  ...\n"
119         "  fun:f?n*2\n"
120         "}";
121     supp_.ReadFromString(data);
122   }
123 };
124 
TEST_F(SuppressionsWithWildcardsTest,Wildcards1)125 TEST_F(SuppressionsWithWildcardsTest, Wildcards1) {
126   string m[] = {"function1", "bb", "function2"};
127   string d[] = {"aaa", "bbb", "ccc"};
128   string o[] = {"object2", "object1", "object3"};
129   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
130 }
131 
TEST_F(SuppressionsWithWildcardsTest,Wildcards2)132 TEST_F(SuppressionsWithWildcardsTest, Wildcards2) {
133   string m[] = {"some_other_function1", "bb", "function2"};
134   string d[] = {"aaa", "bbb", "ccc"};
135   string o[] = {"object2", "object1", "object3"};
136   ASSERT_FALSE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
137 }
138 
TEST_F(SuppressionsWithWildcardsTest,Wildcards3)139 TEST_F(SuppressionsWithWildcardsTest, Wildcards3) {
140   string m[] = {"fun1", "bb", "fanction2"};
141   string d[] = {"aaa", "bbb", "ccc"};
142   string o[] = {"object2", "objt1", "object3"};
143   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
144 }
145 
146 // Tests "..." wildcard.
TEST_F(SuppressionsWithWildcardsTest,VerticalWildcards1)147 TEST_F(SuppressionsWithWildcardsTest, VerticalWildcards1) {
148   string m[] = {"fun1", "bb", "qq", "fanction2"};
149   string d[] = {"aaa", "bbb", "ddd", "ccc"};
150   string o[] = {"object2", "objt1", "object3", "object4"};
151   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
152 }
153 
154 
155 class MultipleStackTraceTest : public BaseSuppressionsTest {
156  protected:
SetUp()157   virtual void SetUp() {
158     const string data =
159         "{\n"
160         "  name\n"
161         "  test_tool,tool2:test_warning_type\n"
162         "  {\n"
163         "    fun:fun*1\n"
164         "  }\n"
165         "  {\n"
166         "    fun:fun*2\n"
167         "    fun:fun*3\n"
168         "  }\n"
169         "  {\n"
170         "    ...\n"
171         "    fun:fun*4\n"
172         "    obj:obj*5\n"
173         "  }\n"
174         "}";
175     supp_.ReadFromString(data);
176   }
177 };
178 
TEST_F(MultipleStackTraceTest,Simple1)179 TEST_F(MultipleStackTraceTest, Simple1) {
180   string m[] = {"fun1", "bb", "qq", "fun2"};
181   string d[] = {"aaa", "bbb", "ddd", "ccc"};
182   string o[] = {"object1", "object2", "object3", "object4"};
183   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
184 }
185 
TEST_F(MultipleStackTraceTest,SecondTemplateMatches)186 TEST_F(MultipleStackTraceTest, SecondTemplateMatches) {
187   string m[] = {"fun2", "fun3", "qq", "fun2"};
188   string d[] = {"aaa", "bbb", "ddd", "ccc"};
189   string o[] = {"object1", "object2", "object3", "object4"};
190   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
191 }
192 
TEST_F(MultipleStackTraceTest,ThirdTemplateMatches)193 TEST_F(MultipleStackTraceTest, ThirdTemplateMatches) {
194   string m[] = {"fun4", "bb", "qq", "fun2"};
195   string d[] = {"aaa", "bbb", "ddd", "ccc"};
196   string o[] = {"object1", "object5", "object3", "object4"};
197   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
198 }
199 
TEST_F(MultipleStackTraceTest,NothingMatches)200 TEST_F(MultipleStackTraceTest, NothingMatches) {
201   string m[] = {"_fun1", "bb", "qq", "fun2"};
202   string d[] = {"aaa", "bbb", "ddd", "ccc"};
203   string o[] = {"object1", "object2", "object3", "object4"};
204   ASSERT_FALSE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
205 }
206 
TEST_F(MultipleStackTraceTest,TwoTemplatesMatch)207 TEST_F(MultipleStackTraceTest, TwoTemplatesMatch) {
208   string m[] = {"fun1", "bb", "fun4", "fun2"};
209   string d[] = {"aaa", "bbb", "ddd", "ccc"};
210   string o[] = {"object1", "object2", "object3", "object5"};
211   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
212 }
213 
214 
TEST_F(BaseSuppressionsTest,StartsWithVerticalWildcard)215 TEST_F(BaseSuppressionsTest, StartsWithVerticalWildcard) {
216   const string data =
217       "{\n"
218       "  name\n"
219       "  test_tool:test_warning_type\n"
220       "  ...\n"
221       "  fun:qq\n"
222       "}";
223   ASSERT_GT(supp_.ReadFromString(data), 0);
224   string m[] = {"fun1", "bb", "qq", "function2"};
225   string d[] = {"aaa", "bbb", "ddd", "ccc"};
226   string o[] = {"object2", "objt1", "object3", "object4"};
227   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
228 }
229 
TEST_F(BaseSuppressionsTest,StartsWithVerticalWildcard2)230 TEST_F(BaseSuppressionsTest, StartsWithVerticalWildcard2) {
231   const string data =
232       "{\n"
233       "  name\n"
234       "  test_tool:test_warning_type\n"
235       "  ...\n"
236       "  fun:fun1\n"
237       "}";
238   ASSERT_GT(supp_.ReadFromString(data), 0);
239   string m[] = {"fun1", "bb", "qq", "function2"};
240   string d[] = {"aaa", "bbb", "ddd", "ccc"};
241   string o[] = {"object2", "objt1", "object3", "object4"};
242   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
243 }
244 
TEST_F(BaseSuppressionsTest,EndsWithVerticalWildcard)245 TEST_F(BaseSuppressionsTest, EndsWithVerticalWildcard) {
246   const string data =
247       "{\n"
248       "  name\n"
249       "  test_tool:test_warning_type\n"
250       "  fun:fun1\n"
251       "  ...\n"
252       "}";
253   ASSERT_GT(supp_.ReadFromString(data), 0);
254   string m[] = {"fun1", "bb", "qq", "function2"};
255   string d[] = {"aaa", "bbb", "ddd", "ccc"};
256   string o[] = {"object2", "objt1", "object3", "object4"};
257   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
258 }
259 
TEST_F(BaseSuppressionsTest,EndsWithVerticalWildcard2)260 TEST_F(BaseSuppressionsTest, EndsWithVerticalWildcard2) {
261   const string data =
262       "{\n"
263       "  name\n"
264       "  test_tool:test_warning_type\n"
265       "  fun:qq\n"
266       "  ...\n"
267       "}";
268   ASSERT_GT(supp_.ReadFromString(data), 0);
269   string m[] = {"fun1", "bb", "qq", "function2"};
270   string d[] = {"aaa", "bbb", "ddd", "ccc"};
271   string o[] = {"object2", "objt1", "object3", "object4"};
272   ASSERT_FALSE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
273 }
274 
TEST_F(BaseSuppressionsTest,Complex)275 TEST_F(BaseSuppressionsTest, Complex) {
276   const string data =
277       "{\n"
278       "  name\n"
279       "  test_tool:test_warning_type\n"
280       "  fun:qq\n"
281       "  ...\n"
282       "  obj:obj*3\n"
283       "  ...\n"
284       "  fun:function?\n"
285       "}";
286   ASSERT_GT(supp_.ReadFromString(data), 0);
287   string m[] = {"fun1", "bb", "qq", "function2"};
288   string d[] = {"aaa", "bbb", "ddd", "ccc"};
289   string o[] = {"object2", "objt1", "object3", "object4"};
290   ASSERT_FALSE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
291 }
292 
TEST_F(BaseSuppressionsTest,DemangledNames)293 TEST_F(BaseSuppressionsTest, DemangledNames) {
294   const string data =
295       "{\n"
296       "  name\n"
297       "  test_tool:test_warning_type\n"
298       "  fun:bb*w?\n"
299       "}";
300   ASSERT_GT(supp_.ReadFromString(data), 0);
301   string m[] = {"fun1", "bb", "qq", "function2"};
302   string d[] = {"bbbxxwz", "aaa", "ddd", "ccc"};
303   string o[] = {"object2", "objt1", "object3", "object4"};
304   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
305 }
306 
TEST_F(BaseSuppressionsTest,TrailingWhitespace)307 TEST_F(BaseSuppressionsTest, TrailingWhitespace) {
308   const string data =
309       "{\n"
310       "  name\n"
311       "  test_tool:test_warning_type\n"
312       "  fun:bb*w? \n"
313       "}";
314   ASSERT_GT(supp_.ReadFromString(data), 0);
315   string m[] = {"fun1", "bb", "qq", "function2"};
316   string d[] = {"bbbxxwz", "aaa", "ddd", "ccc"};
317   string o[] = {"object2", "objt1", "object3", "object4"};
318   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
319 }
320 
TEST_F(BaseSuppressionsTest,ObjectiveC)321 TEST_F(BaseSuppressionsTest, ObjectiveC) {
322   const string data =
323       "{\n"
324       "  name\n"
325       "  test_tool:test_warning_type\n"
326       "  fun:-[NSObject(NSKeyValueCoding) setValue:forKeyPath:]\n"
327       "}";
328   ASSERT_GT(supp_.ReadFromString(data), 0);
329   string m[] = {"-[NSObject(NSKeyValueCoding) setValue:forKeyPath:]", "function2"};
330   string d[] = {"bbbxxwz", "aaa", "ddd", "ccc"};
331   string o[] = {"object2", "objt1", "object3", "object4"};
332   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
333 }
334 
TEST_F(BaseSuppressionsTest,ComparisonAndShiftOperators)335 TEST_F(BaseSuppressionsTest, ComparisonAndShiftOperators) {
336   const string data =
337       "{\n"
338       "  name\n"
339       "  test_tool:test_warning_type\n"
340       "  fun:operator<\n"
341       "  fun:operator>\n"
342       "  fun:operator<=\n"
343       "  fun:operator>=\n"
344       "  fun:operator<<\n"
345       "  fun:operator>>\n"
346       "  fun:operator<<=\n"
347       "  fun:operator>>=\n"
348       "  fun:operator->\n"
349       "  fun:operator->*\n"
350       "}";
351   ASSERT_GT(supp_.ReadFromString(data), 0);
352   string m[] = {"operator<", "operator>", "operator<=", "operator>=",
353                 "operator<<", "operator>>", "operator<<=", "operator>>=",
354                 "operator->", "operator->*"};
355   string d[] = {"bbbxxwz", "aaa", "ddd", "ccc"};
356   string o[] = {"object2", "objt1", "object3", "object4"};
357   ASSERT_TRUE(IsSuppressed(VEC(m), VEC(d), VEC(o)));
358 }
359 
360 
361 class FailingSuppressionsTest : public ::testing::Test {
362  protected:
ErrorLineNo(string data)363   int ErrorLineNo(string data) {
364     int result = supp_.ReadFromString(data);
365     if (result >= 0)
366       return -1;
367     else
368       return supp_.GetErrorLineNo();
369   }
370 
371   Suppressions supp_;
372 };
373 
TEST_F(FailingSuppressionsTest,NoOpeningBrace)374 TEST_F(FailingSuppressionsTest, NoOpeningBrace) {
375   const string data =
376       "  name\n"
377       "  test_tool:test_warning_type\n"
378       "  fun:bb*w? \n"
379       "}";
380   ASSERT_EQ(1, ErrorLineNo(data));
381 }
382 
TEST_F(FailingSuppressionsTest,Bad1)383 TEST_F(FailingSuppressionsTest, Bad1) {
384   const string data =
385       "{\n"
386       "  name\n"
387       "  something_else\n"
388       "  test_tool:test_warning_type\n"
389       "  fun:bb*w? \n"
390       "}";
391   ASSERT_EQ(3, ErrorLineNo(data));
392 }
393 
TEST_F(FailingSuppressionsTest,Bad2)394 TEST_F(FailingSuppressionsTest, Bad2) {
395   const string data =
396       "{\n"
397       "  name\n"
398       "  test_tool:test_warning_type\n"
399       "  extra\n"
400       "  fun:bb*w? \n"
401       "}";
402   ASSERT_EQ(4, ErrorLineNo(data));
403 }
404 
TEST_F(FailingSuppressionsTest,Bad3)405 TEST_F(FailingSuppressionsTest, Bad3) {
406   const string data =
407       "{\n"
408       "  name\n"
409       "  test_tool:test_warning_type\n"
410       "  fun:bb*w? \n"
411       "  extra\n"
412       "}";
413   ASSERT_EQ(5, ErrorLineNo(data));
414 }
415 
TEST_F(FailingSuppressionsTest,SomeWeirdTextAfterASuppression)416 TEST_F(FailingSuppressionsTest, SomeWeirdTextAfterASuppression) {
417   const string data =
418       "{\n"
419       "  name\n"
420       "  test_tool:test_warning_type\n"
421       "  fun:bb*w? \n"
422       "}\n"
423       "some_weird_text\n"
424       "after_a_suppression\n";
425   ASSERT_EQ(6, ErrorLineNo(data));
426 }
427 
TEST_F(FailingSuppressionsTest,NoToolsLineInMultitraceSuppression)428 TEST_F(FailingSuppressionsTest, NoToolsLineInMultitraceSuppression) {
429   const string data =
430       "{\n"
431       "  name\n"
432       "  {\n"
433       "    fun:fun*2\n"
434       "    fun:fun*3\n"
435       "  }\n"
436       "  {\n"
437       "    ...\n"
438       "    fun:fun*4\n"
439       "    obj:obj*5\n"
440       "  }\n"
441       "}";
442   ASSERT_EQ(3, ErrorLineNo(data));
443 }
444 
TEST_F(FailingSuppressionsTest,BadStacktrace1)445 TEST_F(FailingSuppressionsTest, BadStacktrace1) {
446   const string data =
447       "{\n"
448       "  name\n"
449       "  test_tool:test_warning_type\n"
450       "  {\n"
451       "    fun:fun*2\n"
452       "    fun:fun*3\n"
453       "  }\n"
454       "  {\n"
455       "    zzz\n"
456       "    fun:fun*4\n"
457       "    obj:obj*5\n"
458       "  }\n"
459       "}";
460   ASSERT_EQ(9, ErrorLineNo(data));
461 }
462 
TEST_F(FailingSuppressionsTest,BadStacktrace2)463 TEST_F(FailingSuppressionsTest, BadStacktrace2) {
464   const string data =
465       "{\n"
466       "  name\n"
467       "  test_tool:test_warning_type\n"
468       "  {\n"
469       "    fun:fun*2\n"
470       "    fun:fun*3\n"
471       "  }\n"
472       "  {\n"
473       "    {\n"
474       "    fun:fun*4\n"
475       "    obj:obj*5\n"
476       "  }\n"
477       "}";
478   ASSERT_EQ(9, ErrorLineNo(data));
479 }
480 
TEST_F(FailingSuppressionsTest,BadStacktrace3)481 TEST_F(FailingSuppressionsTest, BadStacktrace3) {
482   const string data =
483       "{\n"
484       "  name\n"
485       "  test_tool:test_warning_type\n"
486       "  {\n"
487       "    fun:fun*2\n"
488       "    fun:fun*3\n"
489       "  }\n"
490       "  {\n"
491       "    fun:fun*4\n"
492       "    obj:obj*5\n"
493       "  }\n"
494       "  zzz\n"
495       "}";
496   ASSERT_EQ(12, ErrorLineNo(data));
497 }
498 
TEST_F(FailingSuppressionsTest,StacktraceWithParenthesis)499 TEST_F(FailingSuppressionsTest, StacktraceWithParenthesis) {
500   const string data =
501       "{\n"
502       "  name\n"
503       "  test_tool:test_warning_type\n"
504       "  {\n"
505       "    fun:fun*2\n"
506       "    fun:fun*3\n"
507       "  }\n"
508       "  {\n"
509       "    fun:fun*4()\n"
510       "    obj:obj*5\n"
511       "  }\n"
512       "}";
513   ASSERT_EQ(9, ErrorLineNo(data));
514 }
515 
TEST_F(FailingSuppressionsTest,StacktraceWithAngleBraces)516 TEST_F(FailingSuppressionsTest, StacktraceWithAngleBraces) {
517   const string data =
518       "{\n"
519       "  name\n"
520       "  test_tool:test_warning_type\n"
521       "  {\n"
522       "    fun:fun*2\n"
523       "    fun:fun*3\n"
524       "  }\n"
525       "  {\n"
526       "    fun:fun<int>*4\n"
527       "    obj:obj*5\n"
528       "  }\n"
529       "}";
530   ASSERT_EQ(9, ErrorLineNo(data));
531 }
532 
533 
TEST(WildcardTest,Simple)534 TEST(WildcardTest, Simple) {
535   EXPECT_TRUE(StringMatch("abc", "abc"));
536   EXPECT_FALSE(StringMatch("abcd", "abc"));
537   EXPECT_FALSE(StringMatch("dabc", "abc"));
538   EXPECT_FALSE(StringMatch("ab", "abc"));
539   EXPECT_FALSE(StringMatch("", "abc"));
540   EXPECT_FALSE(StringMatch("abc", ""));
541   EXPECT_TRUE(StringMatch("", ""));
542 }
543 
TEST(WildcardTest,SingleCharacterWildcard)544 TEST(WildcardTest, SingleCharacterWildcard) {
545   EXPECT_TRUE(StringMatch("a?c", "abc"));
546   EXPECT_TRUE(StringMatch("?bc", "abc"));
547   EXPECT_TRUE(StringMatch("ab?", "abc"));
548   EXPECT_TRUE(StringMatch("a??", "abc"));
549   EXPECT_TRUE(StringMatch("???", "abc"));
550   EXPECT_TRUE(StringMatch("?", "a"));
551   EXPECT_FALSE(StringMatch("?zc", "abc"));
552   EXPECT_FALSE(StringMatch("?bz", "abc"));
553   EXPECT_FALSE(StringMatch("b?c", "abc"));
554   EXPECT_FALSE(StringMatch("az?", "abc"));
555   EXPECT_FALSE(StringMatch("abc?", "abc"));
556   EXPECT_FALSE(StringMatch("?abc", "abc"));
557   EXPECT_FALSE(StringMatch("?", ""));
558   EXPECT_FALSE(StringMatch("??", ""));
559 }
560 
TEST(WildcardTest,MultiCharacterWildcard)561 TEST(WildcardTest, MultiCharacterWildcard) {
562   EXPECT_TRUE(StringMatch("*x", "x"));
563   EXPECT_TRUE(StringMatch("x*", "x"));
564   EXPECT_TRUE(StringMatch("*x*", "x"));
565 
566   EXPECT_TRUE(StringMatch("a*d", "abcd"));
567   EXPECT_TRUE(StringMatch("ab*d", "abcd"));
568   EXPECT_TRUE(StringMatch("*cd", "abcd"));
569   EXPECT_TRUE(StringMatch("*d", "abcd"));
570   EXPECT_TRUE(StringMatch("ab*", "abcd"));
571   EXPECT_TRUE(StringMatch("a*", "abcd"));
572   EXPECT_TRUE(StringMatch("*", "abcd"));
573   EXPECT_TRUE(StringMatch("ab*cd", "abcd"));
574 
575   EXPECT_TRUE(StringMatch("ab**", "abcd"));
576   EXPECT_TRUE(StringMatch("**", "abcd"));
577   EXPECT_TRUE(StringMatch("***", "abcd"));
578   EXPECT_TRUE(StringMatch("**d", "abcd"));
579   EXPECT_TRUE(StringMatch("*c*", "abcd"));
580   EXPECT_TRUE(StringMatch("a*c*d*f", "abcdef"));
581   EXPECT_TRUE(StringMatch("a*c*e*", "abcdef"));
582   EXPECT_TRUE(StringMatch("*a*b*f", "abcdef"));
583   EXPECT_TRUE(StringMatch("*b*d*", "abcdef"));
584 
585   EXPECT_FALSE(StringMatch("b*", "abcd"));
586   EXPECT_FALSE(StringMatch("*c", "abcd"));
587   EXPECT_FALSE(StringMatch("*a", "abcd"));
588 }
589 
TEST(WildcardTest,WildcardCharactersInText)590 TEST(WildcardTest, WildcardCharactersInText) {
591   EXPECT_TRUE(StringMatch("?", "?"));
592   EXPECT_FALSE(StringMatch("a", "?"));
593   EXPECT_FALSE(StringMatch("ab", "a?"));
594   EXPECT_FALSE(StringMatch("ab", "?b"));
595   EXPECT_TRUE(StringMatch("a?", "a?"));
596   EXPECT_TRUE(StringMatch("?b", "?b"));
597 
598   EXPECT_TRUE(StringMatch("*", "*"));
599   EXPECT_FALSE(StringMatch("a", "*"));
600   EXPECT_FALSE(StringMatch("ab", "a*"));
601   EXPECT_FALSE(StringMatch("ab", "*b"));
602   EXPECT_TRUE(StringMatch("a*", "a*"));
603   EXPECT_TRUE(StringMatch("*b", "*b"));
604 }
605 
main(int argc,char ** argv)606 int main(int argc, char **argv) {
607   testing::InitGoogleTest(&argc, argv);
608 
609   return RUN_ALL_TESTS();
610 }
611