utils_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package util
  7. import (
  8. "context"
  9. "strings"
  10. "testing"
  11. )
  12. type Defaulter struct {
  13. Value string
  14. }
  15. func (d *Defaulter) ParseDefault(v string) error {
  16. *d = Defaulter{Value: v}
  17. return nil
  18. }
  19. func TestSetDefaults(t *testing.T) {
  20. x := &struct {
  21. A string `default:"string"`
  22. B int `default:"2"`
  23. C float64 `default:"2.2"`
  24. D bool `default:"true"`
  25. E Defaulter `default:"defaulter"`
  26. }{}
  27. if x.A != "" {
  28. t.Error("string failed")
  29. } else if x.B != 0 {
  30. t.Error("int failed")
  31. } else if x.C != 0 {
  32. t.Errorf("float failed")
  33. } else if x.D {
  34. t.Errorf("bool failed")
  35. } else if x.E.Value != "" {
  36. t.Errorf("defaulter failed")
  37. }
  38. SetDefaults(x)
  39. if x.A != "string" {
  40. t.Error("string failed")
  41. } else if x.B != 2 {
  42. t.Error("int failed")
  43. } else if x.C != 2.2 {
  44. t.Errorf("float failed")
  45. } else if !x.D {
  46. t.Errorf("bool failed")
  47. } else if x.E.Value != "defaulter" {
  48. t.Errorf("defaulter failed")
  49. }
  50. }
  51. func TestUniqueStrings(t *testing.T) {
  52. tests := []struct {
  53. input []string
  54. expected []string
  55. }{
  56. {
  57. []string{"a", "b"},
  58. []string{"a", "b"},
  59. },
  60. {
  61. []string{"a", "a"},
  62. []string{"a"},
  63. },
  64. {
  65. []string{"a", "a", "a", "a"},
  66. []string{"a"},
  67. },
  68. {
  69. nil,
  70. nil,
  71. },
  72. {
  73. []string{" a ", " a ", "b ", " b"},
  74. []string{"a", "b"},
  75. },
  76. }
  77. for _, test := range tests {
  78. result := UniqueTrimmedStrings(test.input)
  79. if len(result) != len(test.expected) {
  80. t.Errorf("%s != %s", result, test.expected)
  81. }
  82. for i := range result {
  83. if test.expected[i] != result[i] {
  84. t.Errorf("%s != %s", result, test.expected)
  85. }
  86. }
  87. }
  88. }
  89. func TestFillNillSlices(t *testing.T) {
  90. // Nil
  91. x := &struct {
  92. A []string `default:"a,b"`
  93. }{}
  94. if x.A != nil {
  95. t.Error("not nil")
  96. }
  97. if err := FillNilSlices(x); err != nil {
  98. t.Error(err)
  99. }
  100. if len(x.A) != 2 {
  101. t.Error("length")
  102. }
  103. // Already provided
  104. y := &struct {
  105. A []string `default:"c,d,e"`
  106. }{[]string{"a", "b"}}
  107. if len(y.A) != 2 {
  108. t.Error("length")
  109. }
  110. if err := FillNilSlices(y); err != nil {
  111. t.Error(err)
  112. }
  113. if len(y.A) != 2 {
  114. t.Error("length")
  115. }
  116. // Non-nil but empty
  117. z := &struct {
  118. A []string `default:"c,d,e"`
  119. }{[]string{}}
  120. if len(z.A) != 0 {
  121. t.Error("length")
  122. }
  123. if err := FillNilSlices(z); err != nil {
  124. t.Error(err)
  125. }
  126. if len(z.A) != 0 {
  127. t.Error("length")
  128. }
  129. }
  130. func TestAddress(t *testing.T) {
  131. tests := []struct {
  132. network string
  133. host string
  134. result string
  135. }{
  136. {"tcp", "google.com", "tcp://google.com"},
  137. {"foo", "google", "foo://google"},
  138. {"123", "456", "123://456"},
  139. }
  140. for _, test := range tests {
  141. result := Address(test.network, test.host)
  142. if result != test.result {
  143. t.Errorf("%s != %s", result, test.result)
  144. }
  145. }
  146. }
  147. func TestCopyMatching(t *testing.T) {
  148. type Nested struct {
  149. A int
  150. }
  151. type Test struct {
  152. CopyA int
  153. CopyB []string
  154. CopyC Nested
  155. CopyD *Nested
  156. NoCopy int `restart:"true"`
  157. }
  158. from := Test{
  159. CopyA: 1,
  160. CopyB: []string{"friend", "foe"},
  161. CopyC: Nested{
  162. A: 2,
  163. },
  164. CopyD: &Nested{
  165. A: 3,
  166. },
  167. NoCopy: 4,
  168. }
  169. to := Test{
  170. CopyA: 11,
  171. CopyB: []string{"foot", "toe"},
  172. CopyC: Nested{
  173. A: 22,
  174. },
  175. CopyD: &Nested{
  176. A: 33,
  177. },
  178. NoCopy: 44,
  179. }
  180. // Copy empty fields
  181. CopyMatchingTag(&from, &to, "restart", func(v string) bool {
  182. return v != "true"
  183. })
  184. if to.CopyA != 1 {
  185. t.Error("CopyA")
  186. }
  187. if len(to.CopyB) != 2 || to.CopyB[0] != "friend" || to.CopyB[1] != "foe" {
  188. t.Error("CopyB")
  189. }
  190. if to.CopyC.A != 2 {
  191. t.Error("CopyC")
  192. }
  193. if to.CopyD.A != 3 {
  194. t.Error("CopyC")
  195. }
  196. if to.NoCopy != 44 {
  197. t.Error("NoCopy")
  198. }
  199. }
  200. type mockedAddr struct {
  201. network string
  202. addr string
  203. }
  204. func (a mockedAddr) Network() string {
  205. return a.network
  206. }
  207. func (a mockedAddr) String() string {
  208. return a.addr
  209. }
  210. func TestInspecifiedAddressLess(t *testing.T) {
  211. cases := []struct {
  212. netA string
  213. addrA string
  214. netB string
  215. addrB string
  216. }{
  217. // B is assumed the winner.
  218. {"tcp", "127.0.0.1:1234", "tcp", ":1235"},
  219. {"tcp", "127.0.0.1:1234", "tcp", "0.0.0.0:1235"},
  220. {"tcp4", "0.0.0.0:1234", "tcp", "0.0.0.0:1235"}, // tcp4 on the first one
  221. }
  222. for i, testCase := range cases {
  223. addrs := []mockedAddr{
  224. {testCase.netA, testCase.addrA},
  225. {testCase.netB, testCase.addrB},
  226. }
  227. if AddressUnspecifiedLess(addrs[0], addrs[1]) {
  228. t.Error(i, "unexpected")
  229. }
  230. if !AddressUnspecifiedLess(addrs[1], addrs[0]) {
  231. t.Error(i, "unexpected")
  232. }
  233. if AddressUnspecifiedLess(addrs[0], addrs[0]) || AddressUnspecifiedLess(addrs[1], addrs[1]) {
  234. t.Error(i, "unexpected")
  235. }
  236. }
  237. }
  238. func TestUtilStopTwicePanic(t *testing.T) {
  239. name := "foo"
  240. s := AsService(func(ctx context.Context) {
  241. <-ctx.Done()
  242. }, name)
  243. go s.Serve()
  244. s.Stop()
  245. defer func() {
  246. if r := recover(); r == nil || !strings.Contains(r.(string), name) {
  247. t.Fatalf(`expected panic containing "%v", got "%v"`, name, r)
  248. }
  249. }()
  250. s.Stop()
  251. }