matchergroup_ac_automation_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. package strmatcher_test
  2. import (
  3. "reflect"
  4. "testing"
  5. "github.com/v2fly/v2ray-core/v5/common"
  6. . "github.com/v2fly/v2ray-core/v5/common/strmatcher"
  7. )
  8. func TestACAutomatonMatcherGroup(t *testing.T) {
  9. cases1 := []struct {
  10. pattern string
  11. mType Type
  12. input string
  13. output bool
  14. }{
  15. {
  16. pattern: "v2fly.org",
  17. mType: Domain,
  18. input: "www.v2fly.org",
  19. output: true,
  20. },
  21. {
  22. pattern: "v2fly.org",
  23. mType: Domain,
  24. input: "v2fly.org",
  25. output: true,
  26. },
  27. {
  28. pattern: "v2fly.org",
  29. mType: Domain,
  30. input: "www.v3fly.org",
  31. output: false,
  32. },
  33. {
  34. pattern: "v2fly.org",
  35. mType: Domain,
  36. input: "2fly.org",
  37. output: false,
  38. },
  39. {
  40. pattern: "v2fly.org",
  41. mType: Domain,
  42. input: "xv2fly.org",
  43. output: false,
  44. },
  45. {
  46. pattern: "v2fly.org",
  47. mType: Full,
  48. input: "v2fly.org",
  49. output: true,
  50. },
  51. {
  52. pattern: "v2fly.org",
  53. mType: Full,
  54. input: "xv2fly.org",
  55. output: false,
  56. },
  57. }
  58. for _, test := range cases1 {
  59. ac := NewACAutomatonMatcherGroup()
  60. matcher, err := test.mType.New(test.pattern)
  61. common.Must(err)
  62. common.Must(AddMatcherToGroup(ac, matcher, 0))
  63. ac.Build()
  64. if m := ac.MatchAny(test.input); m != test.output {
  65. t.Error("unexpected output: ", m, " for test case ", test)
  66. }
  67. }
  68. {
  69. cases2Input := []struct {
  70. pattern string
  71. mType Type
  72. }{
  73. {
  74. pattern: "163.com",
  75. mType: Domain,
  76. },
  77. {
  78. pattern: "m.126.com",
  79. mType: Full,
  80. },
  81. {
  82. pattern: "3.com",
  83. mType: Full,
  84. },
  85. {
  86. pattern: "google.com",
  87. mType: Substr,
  88. },
  89. {
  90. pattern: "vgoogle.com",
  91. mType: Substr,
  92. },
  93. }
  94. ac := NewACAutomatonMatcherGroup()
  95. for _, test := range cases2Input {
  96. matcher, err := test.mType.New(test.pattern)
  97. common.Must(err)
  98. common.Must(AddMatcherToGroup(ac, matcher, 0))
  99. }
  100. ac.Build()
  101. cases2Output := []struct {
  102. pattern string
  103. res bool
  104. }{
  105. {
  106. pattern: "126.com",
  107. res: false,
  108. },
  109. {
  110. pattern: "m.163.com",
  111. res: true,
  112. },
  113. {
  114. pattern: "mm163.com",
  115. res: false,
  116. },
  117. {
  118. pattern: "m.126.com",
  119. res: true,
  120. },
  121. {
  122. pattern: "163.com",
  123. res: true,
  124. },
  125. {
  126. pattern: "63.com",
  127. res: false,
  128. },
  129. {
  130. pattern: "oogle.com",
  131. res: false,
  132. },
  133. {
  134. pattern: "vvgoogle.com",
  135. res: true,
  136. },
  137. }
  138. for _, test := range cases2Output {
  139. if m := ac.MatchAny(test.pattern); m != test.res {
  140. t.Error("unexpected output: ", m, " for test case ", test)
  141. }
  142. }
  143. }
  144. {
  145. cases3Input := []struct {
  146. pattern string
  147. mType Type
  148. }{
  149. {
  150. pattern: "video.google.com",
  151. mType: Domain,
  152. },
  153. {
  154. pattern: "gle.com",
  155. mType: Domain,
  156. },
  157. }
  158. ac := NewACAutomatonMatcherGroup()
  159. for _, test := range cases3Input {
  160. matcher, err := test.mType.New(test.pattern)
  161. common.Must(err)
  162. common.Must(AddMatcherToGroup(ac, matcher, 0))
  163. }
  164. ac.Build()
  165. cases3Output := []struct {
  166. pattern string
  167. res bool
  168. }{
  169. {
  170. pattern: "google.com",
  171. res: false,
  172. },
  173. }
  174. for _, test := range cases3Output {
  175. if m := ac.MatchAny(test.pattern); m != test.res {
  176. t.Error("unexpected output: ", m, " for test case ", test)
  177. }
  178. }
  179. }
  180. {
  181. cases4Input := []struct {
  182. pattern string
  183. mType Type
  184. }{
  185. {
  186. pattern: "apis",
  187. mType: Substr,
  188. },
  189. {
  190. pattern: "googleapis.com",
  191. mType: Domain,
  192. },
  193. }
  194. ac := NewACAutomatonMatcherGroup()
  195. for _, test := range cases4Input {
  196. matcher, err := test.mType.New(test.pattern)
  197. common.Must(err)
  198. common.Must(AddMatcherToGroup(ac, matcher, 0))
  199. }
  200. ac.Build()
  201. cases4Output := []struct {
  202. pattern string
  203. res bool
  204. }{
  205. {
  206. pattern: "gapis.com",
  207. res: true,
  208. },
  209. }
  210. for _, test := range cases4Output {
  211. if m := ac.MatchAny(test.pattern); m != test.res {
  212. t.Error("unexpected output: ", m, " for test case ", test)
  213. }
  214. }
  215. }
  216. }
  217. func TestACAutomatonMatcherGroupSubstr(t *testing.T) {
  218. patterns := []struct {
  219. pattern string
  220. mType Type
  221. }{
  222. {
  223. pattern: "apis",
  224. mType: Substr,
  225. },
  226. {
  227. pattern: "google",
  228. mType: Substr,
  229. },
  230. {
  231. pattern: "apis",
  232. mType: Substr,
  233. },
  234. }
  235. cases := []struct {
  236. input string
  237. output []uint32
  238. }{
  239. {
  240. input: "google.com",
  241. output: []uint32{1},
  242. },
  243. {
  244. input: "apis.com",
  245. output: []uint32{0, 2},
  246. },
  247. {
  248. input: "googleapis.com",
  249. output: []uint32{1, 0, 2},
  250. },
  251. {
  252. input: "fonts.googleapis.com",
  253. output: []uint32{1, 0, 2},
  254. },
  255. {
  256. input: "apis.googleapis.com",
  257. output: []uint32{0, 2, 1, 0, 2},
  258. },
  259. }
  260. matcherGroup := NewACAutomatonMatcherGroup()
  261. for id, entry := range patterns {
  262. matcher, err := entry.mType.New(entry.pattern)
  263. common.Must(err)
  264. common.Must(AddMatcherToGroup(matcherGroup, matcher, uint32(id)))
  265. }
  266. matcherGroup.Build()
  267. for _, test := range cases {
  268. if r := matcherGroup.Match(test.input); !reflect.DeepEqual(r, test.output) {
  269. t.Error("unexpected output: ", r, " for test case ", test)
  270. }
  271. }
  272. }
  273. // See https://github.com/v2fly/v2ray-core/issues/92#issuecomment-673238489
  274. func TestACAutomatonMatcherGroupAsIndexMatcher(t *testing.T) {
  275. rules := []struct {
  276. Type Type
  277. Domain string
  278. }{
  279. // Regex not supported by ACAutomationMatcherGroup
  280. // {
  281. // Type: Regex,
  282. // Domain: "apis\\.us$",
  283. // },
  284. {
  285. Type: Substr,
  286. Domain: "apis",
  287. },
  288. {
  289. Type: Domain,
  290. Domain: "googleapis.com",
  291. },
  292. {
  293. Type: Domain,
  294. Domain: "com",
  295. },
  296. {
  297. Type: Full,
  298. Domain: "www.baidu.com",
  299. },
  300. {
  301. Type: Substr,
  302. Domain: "apis",
  303. },
  304. {
  305. Type: Domain,
  306. Domain: "googleapis.com",
  307. },
  308. {
  309. Type: Full,
  310. Domain: "fonts.googleapis.com",
  311. },
  312. {
  313. Type: Full,
  314. Domain: "www.baidu.com",
  315. },
  316. {
  317. Type: Domain,
  318. Domain: "example.com",
  319. },
  320. }
  321. cases := []struct {
  322. Input string
  323. Output []uint32
  324. }{
  325. {
  326. Input: "www.baidu.com",
  327. Output: []uint32{5, 9, 4},
  328. },
  329. {
  330. Input: "fonts.googleapis.com",
  331. Output: []uint32{8, 3, 7, 4, 2, 6},
  332. },
  333. {
  334. Input: "example.googleapis.com",
  335. Output: []uint32{3, 7, 4, 2, 6},
  336. },
  337. {
  338. Input: "testapis.us",
  339. Output: []uint32{2, 6 /*, 1*/},
  340. },
  341. {
  342. Input: "example.com",
  343. Output: []uint32{10, 4},
  344. },
  345. }
  346. matcherGroup := NewACAutomatonMatcherGroup()
  347. for i, rule := range rules {
  348. matcher, err := rule.Type.New(rule.Domain)
  349. common.Must(err)
  350. common.Must(AddMatcherToGroup(matcherGroup, matcher, uint32(i+2)))
  351. }
  352. matcherGroup.Build()
  353. for _, test := range cases {
  354. if m := matcherGroup.Match(test.Input); !reflect.DeepEqual(m, test.Output) {
  355. t.Error("unexpected output: ", m, " for test case ", test)
  356. }
  357. }
  358. }