matchergroup_mph_test.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 TestMphMatcherGroup(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. mph := NewMphMatcherGroup()
  60. matcher, err := test.mType.New(test.pattern)
  61. common.Must(err)
  62. common.Must(AddMatcherToGroup(mph, matcher, 0))
  63. mph.Build()
  64. if m := mph.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. mph := NewMphMatcherGroup()
  87. for _, test := range cases2Input {
  88. matcher, err := test.mType.New(test.pattern)
  89. common.Must(err)
  90. common.Must(AddMatcherToGroup(mph, matcher, 0))
  91. }
  92. mph.Build()
  93. cases2Output := []struct {
  94. pattern string
  95. res bool
  96. }{
  97. {
  98. pattern: "126.com",
  99. res: false,
  100. },
  101. {
  102. pattern: "m.163.com",
  103. res: true,
  104. },
  105. {
  106. pattern: "mm163.com",
  107. res: false,
  108. },
  109. {
  110. pattern: "m.126.com",
  111. res: true,
  112. },
  113. {
  114. pattern: "163.com",
  115. res: true,
  116. },
  117. {
  118. pattern: "63.com",
  119. res: false,
  120. },
  121. {
  122. pattern: "oogle.com",
  123. res: false,
  124. },
  125. {
  126. pattern: "vvgoogle.com",
  127. res: false,
  128. },
  129. }
  130. for _, test := range cases2Output {
  131. if m := mph.MatchAny(test.pattern); m != test.res {
  132. t.Error("unexpected output: ", m, " for test case ", test)
  133. }
  134. }
  135. }
  136. {
  137. cases3Input := []struct {
  138. pattern string
  139. mType Type
  140. }{
  141. {
  142. pattern: "video.google.com",
  143. mType: Domain,
  144. },
  145. {
  146. pattern: "gle.com",
  147. mType: Domain,
  148. },
  149. }
  150. mph := NewMphMatcherGroup()
  151. for _, test := range cases3Input {
  152. matcher, err := test.mType.New(test.pattern)
  153. common.Must(err)
  154. common.Must(AddMatcherToGroup(mph, matcher, 0))
  155. }
  156. mph.Build()
  157. cases3Output := []struct {
  158. pattern string
  159. res bool
  160. }{
  161. {
  162. pattern: "google.com",
  163. res: false,
  164. },
  165. }
  166. for _, test := range cases3Output {
  167. if m := mph.MatchAny(test.pattern); m != test.res {
  168. t.Error("unexpected output: ", m, " for test case ", test)
  169. }
  170. }
  171. }
  172. }
  173. // See https://github.com/v2fly/v2ray-core/issues/92#issuecomment-673238489
  174. func TestMphMatcherGroupAsIndexMatcher(t *testing.T) {
  175. rules := []struct {
  176. Type Type
  177. Domain string
  178. }{
  179. // Regex not supported by MphMatcherGroup
  180. // {
  181. // Type: Regex,
  182. // Domain: "apis\\.us$",
  183. // },
  184. // Substr not supported by MphMatcherGroup
  185. // {
  186. // Type: Substr,
  187. // Domain: "apis",
  188. // },
  189. {
  190. Type: Domain,
  191. Domain: "googleapis.com",
  192. },
  193. {
  194. Type: Domain,
  195. Domain: "com",
  196. },
  197. {
  198. Type: Full,
  199. Domain: "www.baidu.com",
  200. },
  201. // Substr not supported by MphMatcherGroup, We add another matcher to preserve index
  202. {
  203. Type: Domain, // Substr,
  204. Domain: "example.com", // "apis",
  205. },
  206. {
  207. Type: Domain,
  208. Domain: "googleapis.com",
  209. },
  210. {
  211. Type: Full,
  212. Domain: "fonts.googleapis.com",
  213. },
  214. {
  215. Type: Full,
  216. Domain: "www.baidu.com",
  217. },
  218. { // This matcher (index 10) is swapped with matcher (index 6) to test that full matcher takes high priority.
  219. Type: Full,
  220. Domain: "example.com",
  221. },
  222. {
  223. Type: Domain,
  224. Domain: "example.com",
  225. },
  226. }
  227. cases := []struct {
  228. Input string
  229. Output []uint32
  230. }{
  231. {
  232. Input: "www.baidu.com",
  233. Output: []uint32{5, 9, 4},
  234. },
  235. {
  236. Input: "fonts.googleapis.com",
  237. Output: []uint32{8, 3, 7, 4 /*2, 6*/},
  238. },
  239. {
  240. Input: "example.googleapis.com",
  241. Output: []uint32{3, 7, 4 /*2, 6*/},
  242. },
  243. {
  244. Input: "testapis.us",
  245. // Output: []uint32{ /*2, 6*/ /*1,*/ },
  246. Output: nil,
  247. },
  248. {
  249. Input: "example.com",
  250. Output: []uint32{10, 6, 11, 4},
  251. },
  252. }
  253. matcherGroup := NewMphMatcherGroup()
  254. for i, rule := range rules {
  255. matcher, err := rule.Type.New(rule.Domain)
  256. common.Must(err)
  257. common.Must(AddMatcherToGroup(matcherGroup, matcher, uint32(i+3)))
  258. }
  259. matcherGroup.Build()
  260. for _, test := range cases {
  261. if m := matcherGroup.Match(test.Input); !reflect.DeepEqual(m, test.Output) {
  262. t.Error("unexpected output: ", m, " for test case ", test)
  263. }
  264. }
  265. }
  266. func TestEmptyMphMatcherGroup(t *testing.T) {
  267. g := NewMphMatcherGroup()
  268. g.Build()
  269. r := g.Match("v2fly.org")
  270. if len(r) != 0 {
  271. t.Error("Expect [], but ", r)
  272. }
  273. }