github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/common/strmatcher/matchergroup_mph_test.go (about) 1 package strmatcher_test 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/v2fly/v2ray-core/v5/common" 8 . "github.com/v2fly/v2ray-core/v5/common/strmatcher" 9 ) 10 11 func TestMphMatcherGroup(t *testing.T) { 12 cases1 := []struct { 13 pattern string 14 mType Type 15 input string 16 output bool 17 }{ 18 { 19 pattern: "v2fly.org", 20 mType: Domain, 21 input: "www.v2fly.org", 22 output: true, 23 }, 24 { 25 pattern: "v2fly.org", 26 mType: Domain, 27 input: "v2fly.org", 28 output: true, 29 }, 30 { 31 pattern: "v2fly.org", 32 mType: Domain, 33 input: "www.v3fly.org", 34 output: false, 35 }, 36 { 37 pattern: "v2fly.org", 38 mType: Domain, 39 input: "2fly.org", 40 output: false, 41 }, 42 { 43 pattern: "v2fly.org", 44 mType: Domain, 45 input: "xv2fly.org", 46 output: false, 47 }, 48 { 49 pattern: "v2fly.org", 50 mType: Full, 51 input: "v2fly.org", 52 output: true, 53 }, 54 { 55 pattern: "v2fly.org", 56 mType: Full, 57 input: "xv2fly.org", 58 output: false, 59 }, 60 } 61 for _, test := range cases1 { 62 mph := NewMphMatcherGroup() 63 matcher, err := test.mType.New(test.pattern) 64 common.Must(err) 65 common.Must(AddMatcherToGroup(mph, matcher, 0)) 66 mph.Build() 67 if m := mph.MatchAny(test.input); m != test.output { 68 t.Error("unexpected output: ", m, " for test case ", test) 69 } 70 } 71 { 72 cases2Input := []struct { 73 pattern string 74 mType Type 75 }{ 76 { 77 pattern: "163.com", 78 mType: Domain, 79 }, 80 { 81 pattern: "m.126.com", 82 mType: Full, 83 }, 84 { 85 pattern: "3.com", 86 mType: Full, 87 }, 88 } 89 mph := NewMphMatcherGroup() 90 for _, test := range cases2Input { 91 matcher, err := test.mType.New(test.pattern) 92 common.Must(err) 93 common.Must(AddMatcherToGroup(mph, matcher, 0)) 94 } 95 mph.Build() 96 cases2Output := []struct { 97 pattern string 98 res bool 99 }{ 100 { 101 pattern: "126.com", 102 res: false, 103 }, 104 { 105 pattern: "m.163.com", 106 res: true, 107 }, 108 { 109 pattern: "mm163.com", 110 res: false, 111 }, 112 { 113 pattern: "m.126.com", 114 res: true, 115 }, 116 { 117 pattern: "163.com", 118 res: true, 119 }, 120 { 121 pattern: "63.com", 122 res: false, 123 }, 124 { 125 pattern: "oogle.com", 126 res: false, 127 }, 128 { 129 pattern: "vvgoogle.com", 130 res: false, 131 }, 132 } 133 for _, test := range cases2Output { 134 if m := mph.MatchAny(test.pattern); m != test.res { 135 t.Error("unexpected output: ", m, " for test case ", test) 136 } 137 } 138 } 139 { 140 cases3Input := []struct { 141 pattern string 142 mType Type 143 }{ 144 { 145 pattern: "video.google.com", 146 mType: Domain, 147 }, 148 { 149 pattern: "gle.com", 150 mType: Domain, 151 }, 152 } 153 mph := NewMphMatcherGroup() 154 for _, test := range cases3Input { 155 matcher, err := test.mType.New(test.pattern) 156 common.Must(err) 157 common.Must(AddMatcherToGroup(mph, matcher, 0)) 158 } 159 mph.Build() 160 cases3Output := []struct { 161 pattern string 162 res bool 163 }{ 164 { 165 pattern: "google.com", 166 res: false, 167 }, 168 } 169 for _, test := range cases3Output { 170 if m := mph.MatchAny(test.pattern); m != test.res { 171 t.Error("unexpected output: ", m, " for test case ", test) 172 } 173 } 174 } 175 } 176 177 // See https://github.com/v2fly/v2ray-core/issues/92#issuecomment-673238489 178 func TestMphMatcherGroupAsIndexMatcher(t *testing.T) { 179 rules := []struct { 180 Type Type 181 Domain string 182 }{ 183 // Regex not supported by MphMatcherGroup 184 // { 185 // Type: Regex, 186 // Domain: "apis\\.us$", 187 // }, 188 // Substr not supported by MphMatcherGroup 189 // { 190 // Type: Substr, 191 // Domain: "apis", 192 // }, 193 { 194 Type: Domain, 195 Domain: "googleapis.com", 196 }, 197 { 198 Type: Domain, 199 Domain: "com", 200 }, 201 { 202 Type: Full, 203 Domain: "www.baidu.com", 204 }, 205 // Substr not supported by MphMatcherGroup, We add another matcher to preserve index 206 { 207 Type: Domain, // Substr, 208 Domain: "example.com", // "apis", 209 }, 210 { 211 Type: Domain, 212 Domain: "googleapis.com", 213 }, 214 { 215 Type: Full, 216 Domain: "fonts.googleapis.com", 217 }, 218 { 219 Type: Full, 220 Domain: "www.baidu.com", 221 }, 222 { // This matcher (index 10) is swapped with matcher (index 6) to test that full matcher takes high priority. 223 Type: Full, 224 Domain: "example.com", 225 }, 226 { 227 Type: Domain, 228 Domain: "example.com", 229 }, 230 } 231 cases := []struct { 232 Input string 233 Output []uint32 234 }{ 235 { 236 Input: "www.baidu.com", 237 Output: []uint32{5, 9, 4}, 238 }, 239 { 240 Input: "fonts.googleapis.com", 241 Output: []uint32{8, 3, 7, 4 /*2, 6*/}, 242 }, 243 { 244 Input: "example.googleapis.com", 245 Output: []uint32{3, 7, 4 /*2, 6*/}, 246 }, 247 { 248 Input: "testapis.us", 249 // Output: []uint32{ /*2, 6*/ /*1,*/ }, 250 Output: nil, 251 }, 252 { 253 Input: "example.com", 254 Output: []uint32{10, 6, 11, 4}, 255 }, 256 } 257 matcherGroup := NewMphMatcherGroup() 258 for i, rule := range rules { 259 matcher, err := rule.Type.New(rule.Domain) 260 common.Must(err) 261 common.Must(AddMatcherToGroup(matcherGroup, matcher, uint32(i+3))) 262 } 263 matcherGroup.Build() 264 for _, test := range cases { 265 if m := matcherGroup.Match(test.Input); !reflect.DeepEqual(m, test.Output) { 266 t.Error("unexpected output: ", m, " for test case ", test) 267 } 268 } 269 } 270 271 func TestEmptyMphMatcherGroup(t *testing.T) { 272 g := NewMphMatcherGroup() 273 g.Build() 274 r := g.Match("v2fly.org") 275 if len(r) != 0 { 276 t.Error("Expect [], but ", r) 277 } 278 }