github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/common/strmatcher/matchergroup_ac_automation_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 TestACAutomatonMatcherGroup(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 ac := NewACAutomatonMatcherGroup() 63 matcher, err := test.mType.New(test.pattern) 64 common.Must(err) 65 common.Must(AddMatcherToGroup(ac, matcher, 0)) 66 ac.Build() 67 if m := ac.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 pattern: "google.com", 90 mType: Substr, 91 }, 92 { 93 pattern: "vgoogle.com", 94 mType: Substr, 95 }, 96 } 97 ac := NewACAutomatonMatcherGroup() 98 for _, test := range cases2Input { 99 matcher, err := test.mType.New(test.pattern) 100 common.Must(err) 101 common.Must(AddMatcherToGroup(ac, matcher, 0)) 102 } 103 ac.Build() 104 cases2Output := []struct { 105 pattern string 106 res bool 107 }{ 108 { 109 pattern: "126.com", 110 res: false, 111 }, 112 { 113 pattern: "m.163.com", 114 res: true, 115 }, 116 { 117 pattern: "mm163.com", 118 res: false, 119 }, 120 { 121 pattern: "m.126.com", 122 res: true, 123 }, 124 { 125 pattern: "163.com", 126 res: true, 127 }, 128 { 129 pattern: "63.com", 130 res: false, 131 }, 132 { 133 pattern: "oogle.com", 134 res: false, 135 }, 136 { 137 pattern: "vvgoogle.com", 138 res: true, 139 }, 140 } 141 for _, test := range cases2Output { 142 if m := ac.MatchAny(test.pattern); m != test.res { 143 t.Error("unexpected output: ", m, " for test case ", test) 144 } 145 } 146 } 147 148 { 149 cases3Input := []struct { 150 pattern string 151 mType Type 152 }{ 153 { 154 pattern: "video.google.com", 155 mType: Domain, 156 }, 157 { 158 pattern: "gle.com", 159 mType: Domain, 160 }, 161 } 162 ac := NewACAutomatonMatcherGroup() 163 for _, test := range cases3Input { 164 matcher, err := test.mType.New(test.pattern) 165 common.Must(err) 166 common.Must(AddMatcherToGroup(ac, matcher, 0)) 167 } 168 ac.Build() 169 cases3Output := []struct { 170 pattern string 171 res bool 172 }{ 173 { 174 pattern: "google.com", 175 res: false, 176 }, 177 } 178 for _, test := range cases3Output { 179 if m := ac.MatchAny(test.pattern); m != test.res { 180 t.Error("unexpected output: ", m, " for test case ", test) 181 } 182 } 183 } 184 185 { 186 cases4Input := []struct { 187 pattern string 188 mType Type 189 }{ 190 { 191 pattern: "apis", 192 mType: Substr, 193 }, 194 { 195 pattern: "googleapis.com", 196 mType: Domain, 197 }, 198 } 199 ac := NewACAutomatonMatcherGroup() 200 for _, test := range cases4Input { 201 matcher, err := test.mType.New(test.pattern) 202 common.Must(err) 203 common.Must(AddMatcherToGroup(ac, matcher, 0)) 204 } 205 ac.Build() 206 cases4Output := []struct { 207 pattern string 208 res bool 209 }{ 210 { 211 pattern: "gapis.com", 212 res: true, 213 }, 214 } 215 for _, test := range cases4Output { 216 if m := ac.MatchAny(test.pattern); m != test.res { 217 t.Error("unexpected output: ", m, " for test case ", test) 218 } 219 } 220 } 221 } 222 223 func TestACAutomatonMatcherGroupSubstr(t *testing.T) { 224 patterns := []struct { 225 pattern string 226 mType Type 227 }{ 228 { 229 pattern: "apis", 230 mType: Substr, 231 }, 232 { 233 pattern: "google", 234 mType: Substr, 235 }, 236 { 237 pattern: "apis", 238 mType: Substr, 239 }, 240 } 241 cases := []struct { 242 input string 243 output []uint32 244 }{ 245 { 246 input: "google.com", 247 output: []uint32{1}, 248 }, 249 { 250 input: "apis.com", 251 output: []uint32{0, 2}, 252 }, 253 { 254 input: "googleapis.com", 255 output: []uint32{1, 0, 2}, 256 }, 257 { 258 input: "fonts.googleapis.com", 259 output: []uint32{1, 0, 2}, 260 }, 261 { 262 input: "apis.googleapis.com", 263 output: []uint32{0, 2, 1, 0, 2}, 264 }, 265 } 266 matcherGroup := NewACAutomatonMatcherGroup() 267 for id, entry := range patterns { 268 matcher, err := entry.mType.New(entry.pattern) 269 common.Must(err) 270 common.Must(AddMatcherToGroup(matcherGroup, matcher, uint32(id))) 271 } 272 matcherGroup.Build() 273 for _, test := range cases { 274 if r := matcherGroup.Match(test.input); !reflect.DeepEqual(r, test.output) { 275 t.Error("unexpected output: ", r, " for test case ", test) 276 } 277 } 278 } 279 280 // See https://github.com/v2fly/v2ray-core/issues/92#issuecomment-673238489 281 func TestACAutomatonMatcherGroupAsIndexMatcher(t *testing.T) { 282 rules := []struct { 283 Type Type 284 Domain string 285 }{ 286 // Regex not supported by ACAutomationMatcherGroup 287 // { 288 // Type: Regex, 289 // Domain: "apis\\.us$", 290 // }, 291 { 292 Type: Substr, 293 Domain: "apis", 294 }, 295 { 296 Type: Domain, 297 Domain: "googleapis.com", 298 }, 299 { 300 Type: Domain, 301 Domain: "com", 302 }, 303 { 304 Type: Full, 305 Domain: "www.baidu.com", 306 }, 307 { 308 Type: Substr, 309 Domain: "apis", 310 }, 311 { 312 Type: Domain, 313 Domain: "googleapis.com", 314 }, 315 { 316 Type: Full, 317 Domain: "fonts.googleapis.com", 318 }, 319 { 320 Type: Full, 321 Domain: "www.baidu.com", 322 }, 323 { 324 Type: Domain, 325 Domain: "example.com", 326 }, 327 } 328 cases := []struct { 329 Input string 330 Output []uint32 331 }{ 332 { 333 Input: "www.baidu.com", 334 Output: []uint32{5, 9, 4}, 335 }, 336 { 337 Input: "fonts.googleapis.com", 338 Output: []uint32{8, 3, 7, 4, 2, 6}, 339 }, 340 { 341 Input: "example.googleapis.com", 342 Output: []uint32{3, 7, 4, 2, 6}, 343 }, 344 { 345 Input: "testapis.us", 346 Output: []uint32{2, 6 /*, 1*/}, 347 }, 348 { 349 Input: "example.com", 350 Output: []uint32{10, 4}, 351 }, 352 } 353 matcherGroup := NewACAutomatonMatcherGroup() 354 for i, rule := range rules { 355 matcher, err := rule.Type.New(rule.Domain) 356 common.Must(err) 357 common.Must(AddMatcherToGroup(matcherGroup, matcher, uint32(i+2))) 358 } 359 matcherGroup.Build() 360 for _, test := range cases { 361 if m := matcherGroup.Match(test.Input); !reflect.DeepEqual(m, test.Output) { 362 t.Error("unexpected output: ", m, " for test case ", test) 363 } 364 } 365 }