Home | History | Annotate | Download | only in tsan
      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:
     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 
     55 class 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 
     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 
     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.
     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.
     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.
    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:
    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 
    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 
    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 
    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.
    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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    606 int main(int argc, char **argv) {
    607   testing::InitGoogleTest(&argc, argv);
    608 
    609   return RUN_ALL_TESTS();
    610 }
    611