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
38class BaseSuppressionsTest : public ::testing::Test {
39 protected:
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
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
55class SuppressionsTest : public BaseSuppressionsTest {
56 protected:
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
71TEST_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
78TEST_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.
86TEST_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.
94TEST_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.
102TEST_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
109class SuppressionsWithWildcardsTest : public BaseSuppressionsTest {
110 protected:
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
125TEST_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
132TEST_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
139TEST_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.
147TEST_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
155class MultipleStackTraceTest : public BaseSuppressionsTest {
156 protected:
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
179TEST_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
186TEST_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
193TEST_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
200TEST_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
207TEST_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
215TEST_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
230TEST_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
245TEST_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
260TEST_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
275TEST_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
293TEST_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
307TEST_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
321TEST_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
335TEST_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
361class FailingSuppressionsTest : public ::testing::Test {
362 protected:
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
374TEST_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
383TEST_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
394TEST_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
405TEST_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
416TEST_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
428TEST_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
445TEST_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
463TEST_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
481TEST_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
499TEST_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
516TEST_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
534TEST(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
544TEST(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
561TEST(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
590TEST(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
606int main(int argc, char **argv) {
607  testing::InitGoogleTest(&argc, argv);
608
609  return RUN_ALL_TESTS();
610}
611