token_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package geodata
  2. import (
  3. "errors"
  4. "testing"
  5. )
  6. func TestParseReference(t *testing.T) {
  7. tests := []struct {
  8. name string
  9. token string
  10. kind GeoKind
  11. want Reference
  12. wantErr error
  13. }{
  14. {
  15. name: "geosite shorthand",
  16. token: "geosite:google",
  17. kind: KindSite,
  18. want: Reference{File: "geosite.dat", Code: "google"},
  19. },
  20. {
  21. name: "geosite code is case insensitive",
  22. token: "geosite:GOOGLE",
  23. kind: KindSite,
  24. want: Reference{File: "geosite.dat", Code: "google"},
  25. },
  26. {
  27. name: "geosite with attribute",
  28. token: "geosite:google@ads",
  29. kind: KindSite,
  30. want: Reference{File: "geosite.dat", Code: "google", Attributes: []string{"ads"}},
  31. },
  32. {
  33. name: "geosite with several attributes",
  34. token: "geosite:google@ads@cn",
  35. kind: KindSite,
  36. want: Reference{File: "geosite.dat", Code: "google", Attributes: []string{"ads", "cn"}},
  37. },
  38. {
  39. name: "ext form",
  40. token: "ext:my_rules.dat:corp",
  41. kind: KindSite,
  42. want: Reference{File: "my_rules.dat", Code: "corp"},
  43. },
  44. {
  45. name: "ext-site form",
  46. token: "ext-site:my_rules.dat:corp",
  47. kind: KindSite,
  48. want: Reference{File: "my_rules.dat", Code: "corp"},
  49. },
  50. {
  51. name: "ext-domain form",
  52. token: "ext-domain:my_rules.dat:corp",
  53. kind: KindSite,
  54. want: Reference{File: "my_rules.dat", Code: "corp"},
  55. },
  56. {
  57. name: "surrounding spaces",
  58. token: " geosite:google ",
  59. kind: KindSite,
  60. want: Reference{File: "geosite.dat", Code: "google"},
  61. },
  62. {
  63. name: "plain domain needs no database",
  64. token: "google.com",
  65. kind: KindSite,
  66. want: Reference{},
  67. },
  68. {
  69. name: "domain keyword rule needs no database",
  70. token: "keyword:google",
  71. kind: KindSite,
  72. want: Reference{},
  73. },
  74. {
  75. name: "geoip shorthand",
  76. token: "geoip:private",
  77. kind: KindIP,
  78. want: Reference{File: "geoip.dat", Code: "private"},
  79. },
  80. {
  81. name: "geoip reverse before the prefix",
  82. token: "!geoip:cn",
  83. kind: KindIP,
  84. want: Reference{File: "geoip.dat", Code: "cn", Reverse: true},
  85. },
  86. {
  87. name: "geoip reverse before the code",
  88. token: "geoip:!cn",
  89. kind: KindIP,
  90. want: Reference{File: "geoip.dat", Code: "cn", Reverse: true},
  91. },
  92. {
  93. name: "ext-ip form",
  94. token: "ext-ip:my_ips.dat:office",
  95. kind: KindIP,
  96. want: Reference{File: "my_ips.dat", Code: "office"},
  97. },
  98. {
  99. name: "plain cidr needs no database",
  100. token: "10.0.0.0/8",
  101. kind: KindIP,
  102. want: Reference{},
  103. },
  104. {name: "empty token", token: " ", kind: KindSite, wantErr: ErrInvalidToken},
  105. {name: "ext without code", token: "ext:geosite.dat", kind: KindSite, wantErr: ErrInvalidToken},
  106. {name: "ext with empty code", token: "ext:geosite.dat:", kind: KindSite, wantErr: ErrInvalidToken},
  107. {name: "ext with empty file", token: "ext::google", kind: KindSite, wantErr: ErrInvalidToken},
  108. {name: "geosite without code", token: "geosite:", kind: KindSite, wantErr: ErrInvalidToken},
  109. {name: "bare ext prefix", token: "ext:", kind: KindSite, wantErr: ErrInvalidToken},
  110. {name: "geoip token in a domain field", token: "geoip:cn", kind: KindSite, wantErr: ErrWrongKind},
  111. {name: "geosite token in an ip field", token: "geosite:cn", kind: KindIP, wantErr: ErrWrongKind},
  112. {name: "empty attribute", token: "geosite:cn@", kind: KindSite, wantErr: ErrInvalidToken},
  113. {
  114. name: "a space inside the code stays part of the code",
  115. token: "geosite: cn",
  116. kind: KindSite,
  117. want: Reference{File: "geosite.dat", Code: " cn"},
  118. },
  119. {
  120. name: "a space inside an attribute stays part of the attribute",
  121. token: "geosite:cn@ ads",
  122. kind: KindSite,
  123. want: Reference{File: "geosite.dat", Code: "cn", Attributes: []string{" ads"}},
  124. },
  125. {name: "empty attribute between two others", token: "geosite:cn@@ads", kind: KindSite, wantErr: ErrInvalidToken},
  126. {
  127. name: "double negation folds back to a plain match",
  128. token: "!!geoip:cn",
  129. kind: KindIP,
  130. want: Reference{File: "geoip.dat", Code: "cn"},
  131. },
  132. {
  133. name: "negation on both sides of the prefix cancels out",
  134. token: "!geoip:!cn",
  135. kind: KindIP,
  136. want: Reference{File: "geoip.dat", Code: "cn"},
  137. },
  138. {name: "bare ext-ip prefix", token: "ext-ip:", kind: KindIP, wantErr: ErrInvalidToken},
  139. {
  140. name: "an attribute suffix is part of the code for ip rules",
  141. token: "geoip:cn@x",
  142. kind: KindIP,
  143. want: Reference{File: "geoip.dat", Code: "cn@x"},
  144. },
  145. {name: "attribute only", token: "geosite:@ads", kind: KindSite, wantErr: ErrInvalidToken},
  146. }
  147. for _, tt := range tests {
  148. t.Run(tt.name, func(t *testing.T) {
  149. got, err := ParseReference(tt.token, tt.kind)
  150. if tt.wantErr != nil {
  151. if !errors.Is(err, tt.wantErr) {
  152. t.Fatalf("error = %v, want %v", err, tt.wantErr)
  153. }
  154. return
  155. }
  156. if err != nil {
  157. t.Fatalf("unexpected error: %v", err)
  158. }
  159. if got.File != tt.want.File || got.Code != tt.want.Code || got.Reverse != tt.want.Reverse {
  160. t.Errorf("reference = %+v, want %+v", got, tt.want)
  161. }
  162. if len(got.Attributes) != len(tt.want.Attributes) {
  163. t.Fatalf("attributes = %v, want %v", got.Attributes, tt.want.Attributes)
  164. }
  165. for i, attribute := range tt.want.Attributes {
  166. if got.Attributes[i] != attribute {
  167. t.Errorf("attribute %d = %q, want %q", i, got.Attributes[i], attribute)
  168. }
  169. }
  170. })
  171. }
  172. }