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 
    336 class FailingSuppressionsTest : public ::testing::Test {
    337  protected:
    338   int ErrorLineNo(string data) {
    339     int result = supp_.ReadFromString(data);
    340     if (result >= 0)
    341       return -1;
    342     else
    343       return supp_.GetErrorLineNo();
    344   }
    345 
    346   Suppressions supp_;
    347 };
    348 
    349 TEST_F(FailingSuppressionsTest, NoOpeningBrace) {
    350   const string data =
    351       "  name\n"
    352       "  test_tool:test_warning_type\n"
    353       "  fun:bb*w? \n"
    354       "}";
    355   ASSERT_EQ(1, ErrorLineNo(data));
    356 }
    357 
    358 TEST_F(FailingSuppressionsTest, Bad1) {
    359   const string data =
    360       "{\n"
    361       "  name\n"
    362       "  something_else\n"
    363       "  test_tool:test_warning_type\n"
    364       "  fun:bb*w? \n"
    365       "}";
    366   ASSERT_EQ(3, ErrorLineNo(data));
    367 }
    368 
    369 TEST_F(FailingSuppressionsTest, Bad2) {
    370   const string data =
    371       "{\n"
    372       "  name\n"
    373       "  test_tool:test_warning_type\n"
    374       "  extra\n"
    375       "  fun:bb*w? \n"
    376       "}";
    377   ASSERT_EQ(4, ErrorLineNo(data));
    378 }
    379 
    380 TEST_F(FailingSuppressionsTest, Bad3) {
    381   const string data =
    382       "{\n"
    383       "  name\n"
    384       "  test_tool:test_warning_type\n"
    385       "  fun:bb*w? \n"
    386       "  extra\n"
    387       "}";
    388   ASSERT_EQ(5, ErrorLineNo(data));
    389 }
    390 
    391 TEST_F(FailingSuppressionsTest, SomeWeirdTextAfterASuppression) {
    392   const string data =
    393       "{\n"
    394       "  name\n"
    395       "  test_tool:test_warning_type\n"
    396       "  fun:bb*w? \n"
    397       "}\n"
    398       "some_weird_text\n"
    399       "after_a_suppression\n";
    400   ASSERT_EQ(6, ErrorLineNo(data));
    401 }
    402 
    403 TEST_F(FailingSuppressionsTest, NoToolsLineInMultitraceSuppression) {
    404   const string data =
    405       "{\n"
    406       "  name\n"
    407       "  {\n"
    408       "    fun:fun*2\n"
    409       "    fun:fun*3\n"
    410       "  }\n"
    411       "  {\n"
    412       "    ...\n"
    413       "    fun:fun*4\n"
    414       "    obj:obj*5\n"
    415       "  }\n"
    416       "}";
    417   ASSERT_EQ(3, ErrorLineNo(data));
    418 }
    419 
    420 TEST_F(FailingSuppressionsTest, BadStacktrace1) {
    421   const string data =
    422       "{\n"
    423       "  name\n"
    424       "  test_tool:test_warning_type\n"
    425       "  {\n"
    426       "    fun:fun*2\n"
    427       "    fun:fun*3\n"
    428       "  }\n"
    429       "  {\n"
    430       "    zzz\n"
    431       "    fun:fun*4\n"
    432       "    obj:obj*5\n"
    433       "  }\n"
    434       "}";
    435   ASSERT_EQ(9, ErrorLineNo(data));
    436 }
    437 
    438 TEST_F(FailingSuppressionsTest, BadStacktrace2) {
    439   const string data =
    440       "{\n"
    441       "  name\n"
    442       "  test_tool:test_warning_type\n"
    443       "  {\n"
    444       "    fun:fun*2\n"
    445       "    fun:fun*3\n"
    446       "  }\n"
    447       "  {\n"
    448       "    {\n"
    449       "    fun:fun*4\n"
    450       "    obj:obj*5\n"
    451       "  }\n"
    452       "}";
    453   ASSERT_EQ(9, ErrorLineNo(data));
    454 }
    455 
    456 TEST_F(FailingSuppressionsTest, BadStacktrace3) {
    457   const string data =
    458       "{\n"
    459       "  name\n"
    460       "  test_tool:test_warning_type\n"
    461       "  {\n"
    462       "    fun:fun*2\n"
    463       "    fun:fun*3\n"
    464       "  }\n"
    465       "  {\n"
    466       "    fun:fun*4\n"
    467       "    obj:obj*5\n"
    468       "  }\n"
    469       "  zzz\n"
    470       "}";
    471   ASSERT_EQ(12, ErrorLineNo(data));
    472 }
    473 
    474 TEST_F(FailingSuppressionsTest, StacktraceWithParenthesis) {
    475   const string data =
    476       "{\n"
    477       "  name\n"
    478       "  test_tool:test_warning_type\n"
    479       "  {\n"
    480       "    fun:fun*2\n"
    481       "    fun:fun*3\n"
    482       "  }\n"
    483       "  {\n"
    484       "    fun:fun*4()\n"
    485       "    obj:obj*5\n"
    486       "  }\n"
    487       "}";
    488   ASSERT_EQ(9, ErrorLineNo(data));
    489 }
    490 
    491 TEST_F(FailingSuppressionsTest, StacktraceWithAngleBraces) {
    492   const string data =
    493       "{\n"
    494       "  name\n"
    495       "  test_tool:test_warning_type\n"
    496       "  {\n"
    497       "    fun:fun*2\n"
    498       "    fun:fun*3\n"
    499       "  }\n"
    500       "  {\n"
    501       "    fun:fun<int>*4\n"
    502       "    obj:obj*5\n"
    503       "  }\n"
    504       "}";
    505   ASSERT_EQ(9, ErrorLineNo(data));
    506 }
    507 
    508 
    509 TEST(WildcardTest, Simple) {
    510   EXPECT_TRUE(StringMatch("abc", "abc"));
    511   EXPECT_FALSE(StringMatch("abcd", "abc"));
    512   EXPECT_FALSE(StringMatch("dabc", "abc"));
    513   EXPECT_FALSE(StringMatch("ab", "abc"));
    514   EXPECT_FALSE(StringMatch("", "abc"));
    515   EXPECT_FALSE(StringMatch("abc", ""));
    516   EXPECT_TRUE(StringMatch("", ""));
    517 }
    518 
    519 TEST(WildcardTest, SingleCharacterWildcard) {
    520   EXPECT_TRUE(StringMatch("a?c", "abc"));
    521   EXPECT_TRUE(StringMatch("?bc", "abc"));
    522   EXPECT_TRUE(StringMatch("ab?", "abc"));
    523   EXPECT_TRUE(StringMatch("a??", "abc"));
    524   EXPECT_TRUE(StringMatch("???", "abc"));
    525   EXPECT_TRUE(StringMatch("?", "a"));
    526   EXPECT_FALSE(StringMatch("?zc", "abc"));
    527   EXPECT_FALSE(StringMatch("?bz", "abc"));
    528   EXPECT_FALSE(StringMatch("b?c", "abc"));
    529   EXPECT_FALSE(StringMatch("az?", "abc"));
    530   EXPECT_FALSE(StringMatch("abc?", "abc"));
    531   EXPECT_FALSE(StringMatch("?abc", "abc"));
    532   EXPECT_FALSE(StringMatch("?", ""));
    533   EXPECT_FALSE(StringMatch("??", ""));
    534 }
    535 
    536 TEST(WildcardTest, MultiCharacterWildcard) {
    537   EXPECT_TRUE(StringMatch("*x", "x"));
    538   EXPECT_TRUE(StringMatch("x*", "x"));
    539   EXPECT_TRUE(StringMatch("*x*", "x"));
    540 
    541   EXPECT_TRUE(StringMatch("a*d", "abcd"));
    542   EXPECT_TRUE(StringMatch("ab*d", "abcd"));
    543   EXPECT_TRUE(StringMatch("*cd", "abcd"));
    544   EXPECT_TRUE(StringMatch("*d", "abcd"));
    545   EXPECT_TRUE(StringMatch("ab*", "abcd"));
    546   EXPECT_TRUE(StringMatch("a*", "abcd"));
    547   EXPECT_TRUE(StringMatch("*", "abcd"));
    548   EXPECT_TRUE(StringMatch("ab*cd", "abcd"));
    549 
    550   EXPECT_TRUE(StringMatch("ab**", "abcd"));
    551   EXPECT_TRUE(StringMatch("**", "abcd"));
    552   EXPECT_TRUE(StringMatch("***", "abcd"));
    553   EXPECT_TRUE(StringMatch("**d", "abcd"));
    554   EXPECT_TRUE(StringMatch("*c*", "abcd"));
    555   EXPECT_TRUE(StringMatch("a*c*d*f", "abcdef"));
    556   EXPECT_TRUE(StringMatch("a*c*e*", "abcdef"));
    557   EXPECT_TRUE(StringMatch("*a*b*f", "abcdef"));
    558   EXPECT_TRUE(StringMatch("*b*d*", "abcdef"));
    559 
    560   EXPECT_FALSE(StringMatch("b*", "abcd"));
    561   EXPECT_FALSE(StringMatch("*c", "abcd"));
    562   EXPECT_FALSE(StringMatch("*a", "abcd"));
    563 }
    564 
    565 TEST(WildcardTest, WildcardCharactersInText) {
    566   EXPECT_TRUE(StringMatch("?", "?"));
    567   EXPECT_FALSE(StringMatch("a", "?"));
    568   EXPECT_FALSE(StringMatch("ab", "a?"));
    569   EXPECT_FALSE(StringMatch("ab", "?b"));
    570   EXPECT_TRUE(StringMatch("a?", "a?"));
    571   EXPECT_TRUE(StringMatch("?b", "?b"));
    572 
    573   EXPECT_TRUE(StringMatch("*", "*"));
    574   EXPECT_FALSE(StringMatch("a", "*"));
    575   EXPECT_FALSE(StringMatch("ab", "a*"));
    576   EXPECT_FALSE(StringMatch("ab", "*b"));
    577   EXPECT_TRUE(StringMatch("a*", "a*"));
    578   EXPECT_TRUE(StringMatch("*b", "*b"));
    579 }
    580 
    581 int main(int argc, char **argv) {
    582   testing::InitGoogleTest(&argc, argv);
    583 
    584   return RUN_ALL_TESTS();
    585 }
    586