properties_test.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. // Copyright 2018 Frank Schroeder. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package properties
  5. import (
  6. "bytes"
  7. "flag"
  8. "fmt"
  9. "math"
  10. "os"
  11. "reflect"
  12. "strings"
  13. "testing"
  14. "time"
  15. "github.com/magiconair/properties/assert"
  16. )
  17. var verbose = flag.Bool("verbose", false, "Verbose output")
  18. func init() {
  19. ErrorHandler = PanicHandler
  20. }
  21. // ----------------------------------------------------------------------------
  22. // define test cases in the form of
  23. // {"input", "key1", "value1", "key2", "value2", ...}
  24. var complexTests = [][]string{
  25. // whitespace prefix
  26. {" key=value", "key", "value"}, // SPACE prefix
  27. {"\fkey=value", "key", "value"}, // FF prefix
  28. {"\tkey=value", "key", "value"}, // TAB prefix
  29. {" \f\tkey=value", "key", "value"}, // mix prefix
  30. // multiple keys
  31. {"key1=value1\nkey2=value2\n", "key1", "value1", "key2", "value2"},
  32. {"key1=value1\rkey2=value2\r", "key1", "value1", "key2", "value2"},
  33. {"key1=value1\r\nkey2=value2\r\n", "key1", "value1", "key2", "value2"},
  34. // blank lines
  35. {"\nkey=value\n", "key", "value"},
  36. {"\rkey=value\r", "key", "value"},
  37. {"\r\nkey=value\r\n", "key", "value"},
  38. {"\nkey=value\n \nkey2=value2", "key", "value", "key2", "value2"},
  39. {"\nkey=value\n\t\nkey2=value2", "key", "value", "key2", "value2"},
  40. // escaped chars in key
  41. {"k\\ ey = value", "k ey", "value"},
  42. {"k\\:ey = value", "k:ey", "value"},
  43. {"k\\=ey = value", "k=ey", "value"},
  44. {"k\\fey = value", "k\fey", "value"},
  45. {"k\\ney = value", "k\ney", "value"},
  46. {"k\\rey = value", "k\rey", "value"},
  47. {"k\\tey = value", "k\tey", "value"},
  48. // escaped chars in value
  49. {"key = v\\ alue", "key", "v alue"},
  50. {"key = v\\:alue", "key", "v:alue"},
  51. {"key = v\\=alue", "key", "v=alue"},
  52. {"key = v\\falue", "key", "v\falue"},
  53. {"key = v\\nalue", "key", "v\nalue"},
  54. {"key = v\\ralue", "key", "v\ralue"},
  55. {"key = v\\talue", "key", "v\talue"},
  56. // silently dropped escape character
  57. {"k\\zey = value", "kzey", "value"},
  58. {"key = v\\zalue", "key", "vzalue"},
  59. // unicode literals
  60. {"key\\u2318 = value", "key⌘", "value"},
  61. {"k\\u2318ey = value", "k⌘ey", "value"},
  62. {"key = value\\u2318", "key", "value⌘"},
  63. {"key = valu\\u2318e", "key", "valu⌘e"},
  64. // multiline values
  65. {"key = valueA,\\\n valueB", "key", "valueA,valueB"}, // SPACE indent
  66. {"key = valueA,\\\n\f\f\fvalueB", "key", "valueA,valueB"}, // FF indent
  67. {"key = valueA,\\\n\t\t\tvalueB", "key", "valueA,valueB"}, // TAB indent
  68. {"key = valueA,\\\n \f\tvalueB", "key", "valueA,valueB"}, // mix indent
  69. // comments
  70. {"# this is a comment\n! and so is this\nkey1=value1\nkey#2=value#2\n\nkey!3=value!3\n# and another one\n! and the final one", "key1", "value1", "key#2", "value#2", "key!3", "value!3"},
  71. // expansion tests
  72. {"key=value\nkey2=${key}", "key", "value", "key2", "value"},
  73. {"key=value\nkey2=aa${key}", "key", "value", "key2", "aavalue"},
  74. {"key=value\nkey2=${key}bb", "key", "value", "key2", "valuebb"},
  75. {"key=value\nkey2=aa${key}bb", "key", "value", "key2", "aavaluebb"},
  76. {"key=value\nkey2=${key}\nkey3=${key2}", "key", "value", "key2", "value", "key3", "value"},
  77. {"key=value\nkey2=${key}${key}", "key", "value", "key2", "valuevalue"},
  78. {"key=value\nkey2=${key}${key}${key}${key}", "key", "value", "key2", "valuevaluevaluevalue"},
  79. {"key=value\nkey2=${key}${key3}\nkey3=${key}", "key", "value", "key2", "valuevalue", "key3", "value"},
  80. {"key=value\nkey2=${key3}${key}${key4}\nkey3=${key}\nkey4=${key}", "key", "value", "key2", "valuevaluevalue", "key3", "value", "key4", "value"},
  81. {"key=${USER}", "key", os.Getenv("USER")},
  82. {"key=${USER}\nUSER=value", "key", "value", "USER", "value"},
  83. }
  84. // ----------------------------------------------------------------------------
  85. var commentTests = []struct {
  86. input, key, value string
  87. comments []string
  88. }{
  89. {"key=value", "key", "value", nil},
  90. {"#\nkey=value", "key", "value", []string{""}},
  91. {"#comment\nkey=value", "key", "value", []string{"comment"}},
  92. {"# comment\nkey=value", "key", "value", []string{"comment"}},
  93. {"# comment\nkey=value", "key", "value", []string{"comment"}},
  94. {"# comment\n\nkey=value", "key", "value", []string{"comment"}},
  95. {"# comment1\n# comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}},
  96. {"# comment1\n\n# comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}},
  97. {"!comment\nkey=value", "key", "value", []string{"comment"}},
  98. {"! comment\nkey=value", "key", "value", []string{"comment"}},
  99. {"! comment\nkey=value", "key", "value", []string{"comment"}},
  100. {"! comment\n\nkey=value", "key", "value", []string{"comment"}},
  101. {"! comment1\n! comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}},
  102. {"! comment1\n\n! comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}},
  103. }
  104. // ----------------------------------------------------------------------------
  105. var errorTests = []struct {
  106. input, msg string
  107. }{
  108. // unicode literals
  109. {"key\\u1 = value", "invalid unicode literal"},
  110. {"key\\u12 = value", "invalid unicode literal"},
  111. {"key\\u123 = value", "invalid unicode literal"},
  112. {"key\\u123g = value", "invalid unicode literal"},
  113. {"key\\u123", "invalid unicode literal"},
  114. // circular references
  115. {"key=${key}", "circular reference"},
  116. {"key1=${key2}\nkey2=${key1}", "circular reference"},
  117. // malformed expressions
  118. {"key=${ke", "malformed expression"},
  119. {"key=valu${ke", "malformed expression"},
  120. }
  121. // ----------------------------------------------------------------------------
  122. var writeTests = []struct {
  123. input, output, encoding string
  124. }{
  125. // ISO-8859-1 tests
  126. {"key = value", "key = value\n", "ISO-8859-1"},
  127. {"key = value \\\n continued", "key = value continued\n", "ISO-8859-1"},
  128. {"key⌘ = value", "key\\u2318 = value\n", "ISO-8859-1"},
  129. {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "ISO-8859-1"},
  130. // UTF-8 tests
  131. {"key = value", "key = value\n", "UTF-8"},
  132. {"key = value \\\n continued", "key = value continued\n", "UTF-8"},
  133. {"key⌘ = value⌘", "key⌘ = value⌘\n", "UTF-8"},
  134. {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "UTF-8"},
  135. }
  136. // ----------------------------------------------------------------------------
  137. var writeCommentTests = []struct {
  138. input, output, encoding string
  139. }{
  140. // ISO-8859-1 tests
  141. {"key = value", "key = value\n", "ISO-8859-1"},
  142. {"#\nkey = value", "key = value\n", "ISO-8859-1"},
  143. {"#\n#\n#\nkey = value", "key = value\n", "ISO-8859-1"},
  144. {"# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
  145. {"\n# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
  146. {"# comment\n\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
  147. {"# comment1\n# comment2\nkey = value", "# comment1\n# comment2\nkey = value\n", "ISO-8859-1"},
  148. {"#comment1\nkey1 = value1\n#comment2\nkey2 = value2", "# comment1\nkey1 = value1\n\n# comment2\nkey2 = value2\n", "ISO-8859-1"},
  149. // UTF-8 tests
  150. {"key = value", "key = value\n", "UTF-8"},
  151. {"# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
  152. {"\n# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
  153. {"# comment⌘\n\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
  154. {"# comment1⌘\n# comment2⌘\nkey = value⌘", "# comment1⌘\n# comment2⌘\nkey = value⌘\n", "UTF-8"},
  155. {"#comment1⌘\nkey1 = value1⌘\n#comment2⌘\nkey2 = value2⌘", "# comment1⌘\nkey1 = value1⌘\n\n# comment2⌘\nkey2 = value2⌘\n", "UTF-8"},
  156. }
  157. // ----------------------------------------------------------------------------
  158. var boolTests = []struct {
  159. input, key string
  160. def, value bool
  161. }{
  162. // valid values for TRUE
  163. {"key = 1", "key", false, true},
  164. {"key = on", "key", false, true},
  165. {"key = On", "key", false, true},
  166. {"key = ON", "key", false, true},
  167. {"key = true", "key", false, true},
  168. {"key = True", "key", false, true},
  169. {"key = TRUE", "key", false, true},
  170. {"key = yes", "key", false, true},
  171. {"key = Yes", "key", false, true},
  172. {"key = YES", "key", false, true},
  173. // valid values for FALSE (all other)
  174. {"key = 0", "key", true, false},
  175. {"key = off", "key", true, false},
  176. {"key = false", "key", true, false},
  177. {"key = no", "key", true, false},
  178. // non existent key
  179. {"key = true", "key2", false, false},
  180. }
  181. // ----------------------------------------------------------------------------
  182. var durationTests = []struct {
  183. input, key string
  184. def, value time.Duration
  185. }{
  186. // valid values
  187. {"key = 1", "key", 999, 1},
  188. {"key = 0", "key", 999, 0},
  189. {"key = -1", "key", 999, -1},
  190. {"key = 0123", "key", 999, 123},
  191. // invalid values
  192. {"key = 0xff", "key", 999, 999},
  193. {"key = 1.0", "key", 999, 999},
  194. {"key = a", "key", 999, 999},
  195. // non existent key
  196. {"key = 1", "key2", 999, 999},
  197. }
  198. // ----------------------------------------------------------------------------
  199. var parsedDurationTests = []struct {
  200. input, key string
  201. def, value time.Duration
  202. }{
  203. // valid values
  204. {"key = -1ns", "key", 999, -1 * time.Nanosecond},
  205. {"key = 300ms", "key", 999, 300 * time.Millisecond},
  206. {"key = 5s", "key", 999, 5 * time.Second},
  207. {"key = 3h", "key", 999, 3 * time.Hour},
  208. {"key = 2h45m", "key", 999, 2*time.Hour + 45*time.Minute},
  209. // invalid values
  210. {"key = 0xff", "key", 999, 999},
  211. {"key = 1.0", "key", 999, 999},
  212. {"key = a", "key", 999, 999},
  213. {"key = 1", "key", 999, 999},
  214. {"key = 0", "key", 999, 0},
  215. // non existent key
  216. {"key = 1", "key2", 999, 999},
  217. }
  218. // ----------------------------------------------------------------------------
  219. var floatTests = []struct {
  220. input, key string
  221. def, value float64
  222. }{
  223. // valid values
  224. {"key = 1.0", "key", 999, 1.0},
  225. {"key = 0.0", "key", 999, 0.0},
  226. {"key = -1.0", "key", 999, -1.0},
  227. {"key = 1", "key", 999, 1},
  228. {"key = 0", "key", 999, 0},
  229. {"key = -1", "key", 999, -1},
  230. {"key = 0123", "key", 999, 123},
  231. // invalid values
  232. {"key = 0xff", "key", 999, 999},
  233. {"key = a", "key", 999, 999},
  234. // non existent key
  235. {"key = 1", "key2", 999, 999},
  236. }
  237. // ----------------------------------------------------------------------------
  238. var int64Tests = []struct {
  239. input, key string
  240. def, value int64
  241. }{
  242. // valid values
  243. {"key = 1", "key", 999, 1},
  244. {"key = 0", "key", 999, 0},
  245. {"key = -1", "key", 999, -1},
  246. {"key = 0123", "key", 999, 123},
  247. // invalid values
  248. {"key = 0xff", "key", 999, 999},
  249. {"key = 1.0", "key", 999, 999},
  250. {"key = a", "key", 999, 999},
  251. // non existent key
  252. {"key = 1", "key2", 999, 999},
  253. }
  254. // ----------------------------------------------------------------------------
  255. var uint64Tests = []struct {
  256. input, key string
  257. def, value uint64
  258. }{
  259. // valid values
  260. {"key = 1", "key", 999, 1},
  261. {"key = 0", "key", 999, 0},
  262. {"key = 0123", "key", 999, 123},
  263. // invalid values
  264. {"key = -1", "key", 999, 999},
  265. {"key = 0xff", "key", 999, 999},
  266. {"key = 1.0", "key", 999, 999},
  267. {"key = a", "key", 999, 999},
  268. // non existent key
  269. {"key = 1", "key2", 999, 999},
  270. }
  271. // ----------------------------------------------------------------------------
  272. var stringTests = []struct {
  273. input, key string
  274. def, value string
  275. }{
  276. // valid values
  277. {"key = abc", "key", "def", "abc"},
  278. // non existent key
  279. {"key = abc", "key2", "def", "def"},
  280. }
  281. // ----------------------------------------------------------------------------
  282. var keysTests = []struct {
  283. input string
  284. keys []string
  285. }{
  286. {"", []string{}},
  287. {"key = abc", []string{"key"}},
  288. {"key = abc\nkey2=def", []string{"key", "key2"}},
  289. {"key2 = abc\nkey=def", []string{"key2", "key"}},
  290. {"key = abc\nkey=def", []string{"key"}},
  291. }
  292. // ----------------------------------------------------------------------------
  293. var filterTests = []struct {
  294. input string
  295. pattern string
  296. keys []string
  297. err string
  298. }{
  299. {"", "", []string{}, ""},
  300. {"", "abc", []string{}, ""},
  301. {"key=value", "", []string{"key"}, ""},
  302. {"key=value", "key=", []string{}, ""},
  303. {"key=value\nfoo=bar", "", []string{"foo", "key"}, ""},
  304. {"key=value\nfoo=bar", "f", []string{"foo"}, ""},
  305. {"key=value\nfoo=bar", "fo", []string{"foo"}, ""},
  306. {"key=value\nfoo=bar", "foo", []string{"foo"}, ""},
  307. {"key=value\nfoo=bar", "fooo", []string{}, ""},
  308. {"key=value\nkey2=value2\nfoo=bar", "ey", []string{"key", "key2"}, ""},
  309. {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}, ""},
  310. {"key=value\nkey2=value2\nfoo=bar", "^key", []string{"key", "key2"}, ""},
  311. {"key=value\nkey2=value2\nfoo=bar", "^(key|foo)", []string{"foo", "key", "key2"}, ""},
  312. {"key=value\nkey2=value2\nfoo=bar", "[ abc", nil, "error parsing regexp.*"},
  313. }
  314. // ----------------------------------------------------------------------------
  315. var filterPrefixTests = []struct {
  316. input string
  317. prefix string
  318. keys []string
  319. }{
  320. {"", "", []string{}},
  321. {"", "abc", []string{}},
  322. {"key=value", "", []string{"key"}},
  323. {"key=value", "key=", []string{}},
  324. {"key=value\nfoo=bar", "", []string{"foo", "key"}},
  325. {"key=value\nfoo=bar", "f", []string{"foo"}},
  326. {"key=value\nfoo=bar", "fo", []string{"foo"}},
  327. {"key=value\nfoo=bar", "foo", []string{"foo"}},
  328. {"key=value\nfoo=bar", "fooo", []string{}},
  329. {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}},
  330. }
  331. // ----------------------------------------------------------------------------
  332. var filterStripPrefixTests = []struct {
  333. input string
  334. prefix string
  335. keys []string
  336. }{
  337. {"", "", []string{}},
  338. {"", "abc", []string{}},
  339. {"key=value", "", []string{"key"}},
  340. {"key=value", "key=", []string{}},
  341. {"key=value\nfoo=bar", "", []string{"foo", "key"}},
  342. {"key=value\nfoo=bar", "f", []string{"foo"}},
  343. {"key=value\nfoo=bar", "fo", []string{"foo"}},
  344. {"key=value\nfoo=bar", "foo", []string{"foo"}},
  345. {"key=value\nfoo=bar", "fooo", []string{}},
  346. {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}},
  347. }
  348. // ----------------------------------------------------------------------------
  349. var setTests = []struct {
  350. input string
  351. key, value string
  352. prev string
  353. ok bool
  354. err string
  355. keys []string
  356. }{
  357. {"", "", "", "", false, "", []string{}},
  358. {"", "key", "value", "", false, "", []string{"key"}},
  359. {"key=value", "key2", "value2", "", false, "", []string{"key", "key2"}},
  360. {"key=value", "abc", "value3", "", false, "", []string{"key", "abc"}},
  361. {"key=value", "key", "value3", "value", true, "", []string{"key"}},
  362. }
  363. // ----------------------------------------------------------------------------
  364. // TestBasic tests basic single key/value combinations with all possible
  365. // whitespace, delimiter and newline permutations.
  366. func TestBasic(t *testing.T) {
  367. testWhitespaceAndDelimiterCombinations(t, "key", "")
  368. testWhitespaceAndDelimiterCombinations(t, "key", "value")
  369. testWhitespaceAndDelimiterCombinations(t, "key", "value ")
  370. }
  371. func TestComplex(t *testing.T) {
  372. for _, test := range complexTests {
  373. testKeyValue(t, test[0], test[1:]...)
  374. }
  375. }
  376. func TestErrors(t *testing.T) {
  377. for _, test := range errorTests {
  378. _, err := Load([]byte(test.input), ISO_8859_1)
  379. assert.Equal(t, err != nil, true, "want error")
  380. assert.Equal(t, strings.Contains(err.Error(), test.msg), true)
  381. }
  382. }
  383. func TestVeryDeep(t *testing.T) {
  384. input := "key0=value\n"
  385. prefix := "${"
  386. postfix := "}"
  387. i := 0
  388. for i = 0; i < maxExpansionDepth-1; i++ {
  389. input += fmt.Sprintf("key%d=%skey%d%s\n", i+1, prefix, i, postfix)
  390. }
  391. p, err := Load([]byte(input), ISO_8859_1)
  392. assert.Equal(t, err, nil)
  393. p.Prefix = prefix
  394. p.Postfix = postfix
  395. assert.Equal(t, p.MustGet(fmt.Sprintf("key%d", i)), "value")
  396. // Nudge input over the edge
  397. input += fmt.Sprintf("key%d=%skey%d%s\n", i+1, prefix, i, postfix)
  398. _, err = Load([]byte(input), ISO_8859_1)
  399. assert.Equal(t, err != nil, true, "want error")
  400. assert.Equal(t, strings.Contains(err.Error(), "expansion too deep"), true)
  401. }
  402. func TestDisableExpansion(t *testing.T) {
  403. input := "key=value\nkey2=${key}"
  404. p := mustParse(t, input)
  405. p.DisableExpansion = true
  406. assert.Equal(t, p.MustGet("key"), "value")
  407. assert.Equal(t, p.MustGet("key2"), "${key}")
  408. // with expansion disabled we can introduce circular references
  409. p.MustSet("keyA", "${keyB}")
  410. p.MustSet("keyB", "${keyA}")
  411. assert.Equal(t, p.MustGet("keyA"), "${keyB}")
  412. assert.Equal(t, p.MustGet("keyB"), "${keyA}")
  413. }
  414. func TestDisableExpansionStillUpdatesKeys(t *testing.T) {
  415. p := NewProperties()
  416. p.MustSet("p1", "a")
  417. assert.Equal(t, p.Keys(), []string{"p1"})
  418. assert.Equal(t, p.String(), "p1 = a\n")
  419. p.DisableExpansion = true
  420. p.MustSet("p2", "b")
  421. assert.Equal(t, p.Keys(), []string{"p1", "p2"})
  422. assert.Equal(t, p.String(), "p1 = a\np2 = b\n")
  423. }
  424. func TestMustGet(t *testing.T) {
  425. input := "key = value\nkey2 = ghi"
  426. p := mustParse(t, input)
  427. assert.Equal(t, p.MustGet("key"), "value")
  428. assert.Panic(t, func() { p.MustGet("invalid") }, "unknown property: invalid")
  429. }
  430. func TestGetBool(t *testing.T) {
  431. for _, test := range boolTests {
  432. p := mustParse(t, test.input)
  433. assert.Equal(t, p.Len(), 1)
  434. assert.Equal(t, p.GetBool(test.key, test.def), test.value)
  435. }
  436. }
  437. func TestMustGetBool(t *testing.T) {
  438. input := "key = true\nkey2 = ghi"
  439. p := mustParse(t, input)
  440. assert.Equal(t, p.MustGetBool("key"), true)
  441. assert.Panic(t, func() { p.MustGetBool("invalid") }, "unknown property: invalid")
  442. }
  443. func TestGetDuration(t *testing.T) {
  444. for _, test := range durationTests {
  445. p := mustParse(t, test.input)
  446. assert.Equal(t, p.Len(), 1)
  447. assert.Equal(t, p.GetDuration(test.key, test.def), test.value)
  448. }
  449. }
  450. func TestMustGetDuration(t *testing.T) {
  451. input := "key = 123\nkey2 = ghi"
  452. p := mustParse(t, input)
  453. assert.Equal(t, p.MustGetDuration("key"), time.Duration(123))
  454. assert.Panic(t, func() { p.MustGetDuration("key2") }, "strconv.ParseInt: parsing.*")
  455. assert.Panic(t, func() { p.MustGetDuration("invalid") }, "unknown property: invalid")
  456. }
  457. func TestGetParsedDuration(t *testing.T) {
  458. for _, test := range parsedDurationTests {
  459. p := mustParse(t, test.input)
  460. assert.Equal(t, p.Len(), 1)
  461. assert.Equal(t, p.GetParsedDuration(test.key, test.def), test.value)
  462. }
  463. }
  464. func TestMustGetParsedDuration(t *testing.T) {
  465. input := "key = 123ms\nkey2 = ghi"
  466. p := mustParse(t, input)
  467. assert.Equal(t, p.MustGetParsedDuration("key"), 123*time.Millisecond)
  468. assert.Panic(t, func() { p.MustGetParsedDuration("key2") }, "time: invalid duration ghi")
  469. assert.Panic(t, func() { p.MustGetParsedDuration("invalid") }, "unknown property: invalid")
  470. }
  471. func TestGetFloat64(t *testing.T) {
  472. for _, test := range floatTests {
  473. p := mustParse(t, test.input)
  474. assert.Equal(t, p.Len(), 1)
  475. assert.Equal(t, p.GetFloat64(test.key, test.def), test.value)
  476. }
  477. }
  478. func TestMustGetFloat64(t *testing.T) {
  479. input := "key = 123\nkey2 = ghi"
  480. p := mustParse(t, input)
  481. assert.Equal(t, p.MustGetFloat64("key"), float64(123))
  482. assert.Panic(t, func() { p.MustGetFloat64("key2") }, "strconv.ParseFloat: parsing.*")
  483. assert.Panic(t, func() { p.MustGetFloat64("invalid") }, "unknown property: invalid")
  484. }
  485. func TestGetInt(t *testing.T) {
  486. for _, test := range int64Tests {
  487. p := mustParse(t, test.input)
  488. assert.Equal(t, p.Len(), 1)
  489. assert.Equal(t, p.GetInt(test.key, int(test.def)), int(test.value))
  490. }
  491. }
  492. func TestMustGetInt(t *testing.T) {
  493. input := "key = 123\nkey2 = ghi"
  494. p := mustParse(t, input)
  495. assert.Equal(t, p.MustGetInt("key"), int(123))
  496. assert.Panic(t, func() { p.MustGetInt("key2") }, "strconv.ParseInt: parsing.*")
  497. assert.Panic(t, func() { p.MustGetInt("invalid") }, "unknown property: invalid")
  498. }
  499. func TestGetInt64(t *testing.T) {
  500. for _, test := range int64Tests {
  501. p := mustParse(t, test.input)
  502. assert.Equal(t, p.Len(), 1)
  503. assert.Equal(t, p.GetInt64(test.key, test.def), test.value)
  504. }
  505. }
  506. func TestMustGetInt64(t *testing.T) {
  507. input := "key = 123\nkey2 = ghi"
  508. p := mustParse(t, input)
  509. assert.Equal(t, p.MustGetInt64("key"), int64(123))
  510. assert.Panic(t, func() { p.MustGetInt64("key2") }, "strconv.ParseInt: parsing.*")
  511. assert.Panic(t, func() { p.MustGetInt64("invalid") }, "unknown property: invalid")
  512. }
  513. func TestGetUint(t *testing.T) {
  514. for _, test := range uint64Tests {
  515. p := mustParse(t, test.input)
  516. assert.Equal(t, p.Len(), 1)
  517. assert.Equal(t, p.GetUint(test.key, uint(test.def)), uint(test.value))
  518. }
  519. }
  520. func TestMustGetUint(t *testing.T) {
  521. input := "key = 123\nkey2 = ghi"
  522. p := mustParse(t, input)
  523. assert.Equal(t, p.MustGetUint("key"), uint(123))
  524. assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*")
  525. assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid")
  526. }
  527. func TestGetUint64(t *testing.T) {
  528. for _, test := range uint64Tests {
  529. p := mustParse(t, test.input)
  530. assert.Equal(t, p.Len(), 1)
  531. assert.Equal(t, p.GetUint64(test.key, test.def), test.value)
  532. }
  533. }
  534. func TestMustGetUint64(t *testing.T) {
  535. input := "key = 123\nkey2 = ghi"
  536. p := mustParse(t, input)
  537. assert.Equal(t, p.MustGetUint64("key"), uint64(123))
  538. assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*")
  539. assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid")
  540. }
  541. func TestGetString(t *testing.T) {
  542. for _, test := range stringTests {
  543. p := mustParse(t, test.input)
  544. assert.Equal(t, p.Len(), 1)
  545. assert.Equal(t, p.GetString(test.key, test.def), test.value)
  546. }
  547. }
  548. func TestMustGetString(t *testing.T) {
  549. input := `key = value`
  550. p := mustParse(t, input)
  551. assert.Equal(t, p.MustGetString("key"), "value")
  552. assert.Panic(t, func() { p.MustGetString("invalid") }, "unknown property: invalid")
  553. }
  554. func TestComment(t *testing.T) {
  555. for _, test := range commentTests {
  556. p := mustParse(t, test.input)
  557. assert.Equal(t, p.MustGetString(test.key), test.value)
  558. assert.Equal(t, p.GetComments(test.key), test.comments)
  559. if test.comments != nil {
  560. assert.Equal(t, p.GetComment(test.key), test.comments[len(test.comments)-1])
  561. } else {
  562. assert.Equal(t, p.GetComment(test.key), "")
  563. }
  564. // test setting comments
  565. if len(test.comments) > 0 {
  566. // set single comment
  567. p.ClearComments()
  568. assert.Equal(t, len(p.c), 0)
  569. p.SetComment(test.key, test.comments[0])
  570. assert.Equal(t, p.GetComment(test.key), test.comments[0])
  571. // set multiple comments
  572. p.ClearComments()
  573. assert.Equal(t, len(p.c), 0)
  574. p.SetComments(test.key, test.comments)
  575. assert.Equal(t, p.GetComments(test.key), test.comments)
  576. // clear comments for a key
  577. p.SetComments(test.key, nil)
  578. assert.Equal(t, p.GetComment(test.key), "")
  579. assert.Equal(t, p.GetComments(test.key), ([]string)(nil))
  580. }
  581. }
  582. }
  583. func TestFilter(t *testing.T) {
  584. for _, test := range filterTests {
  585. p := mustParse(t, test.input)
  586. pp, err := p.Filter(test.pattern)
  587. if err != nil {
  588. assert.Matches(t, err.Error(), test.err)
  589. continue
  590. }
  591. assert.Equal(t, pp != nil, true, "want properties")
  592. assert.Equal(t, pp.Len(), len(test.keys))
  593. for _, key := range test.keys {
  594. v1, ok1 := p.Get(key)
  595. v2, ok2 := pp.Get(key)
  596. assert.Equal(t, ok1, true)
  597. assert.Equal(t, ok2, true)
  598. assert.Equal(t, v1, v2)
  599. }
  600. }
  601. }
  602. func TestFilterPrefix(t *testing.T) {
  603. for _, test := range filterPrefixTests {
  604. p := mustParse(t, test.input)
  605. pp := p.FilterPrefix(test.prefix)
  606. assert.Equal(t, pp != nil, true, "want properties")
  607. assert.Equal(t, pp.Len(), len(test.keys))
  608. for _, key := range test.keys {
  609. v1, ok1 := p.Get(key)
  610. v2, ok2 := pp.Get(key)
  611. assert.Equal(t, ok1, true)
  612. assert.Equal(t, ok2, true)
  613. assert.Equal(t, v1, v2)
  614. }
  615. }
  616. }
  617. func TestFilterStripPrefix(t *testing.T) {
  618. for _, test := range filterStripPrefixTests {
  619. p := mustParse(t, test.input)
  620. pp := p.FilterPrefix(test.prefix)
  621. assert.Equal(t, pp != nil, true, "want properties")
  622. assert.Equal(t, pp.Len(), len(test.keys))
  623. for _, key := range test.keys {
  624. v1, ok1 := p.Get(key)
  625. v2, ok2 := pp.Get(key)
  626. assert.Equal(t, ok1, true)
  627. assert.Equal(t, ok2, true)
  628. assert.Equal(t, v1, v2)
  629. }
  630. }
  631. }
  632. func TestKeys(t *testing.T) {
  633. for _, test := range keysTests {
  634. p := mustParse(t, test.input)
  635. assert.Equal(t, p.Len(), len(test.keys))
  636. assert.Equal(t, len(p.Keys()), len(test.keys))
  637. assert.Equal(t, p.Keys(), test.keys)
  638. }
  639. }
  640. func TestSet(t *testing.T) {
  641. for _, test := range setTests {
  642. p := mustParse(t, test.input)
  643. prev, ok, err := p.Set(test.key, test.value)
  644. if test.err != "" {
  645. assert.Matches(t, err.Error(), test.err)
  646. continue
  647. }
  648. assert.Equal(t, err, nil)
  649. assert.Equal(t, ok, test.ok)
  650. if ok {
  651. assert.Equal(t, prev, test.prev)
  652. }
  653. assert.Equal(t, p.Keys(), test.keys)
  654. }
  655. }
  656. func TestSetValue(t *testing.T) {
  657. tests := []interface{}{
  658. true, false,
  659. int8(123), int16(123), int32(123), int64(123), int(123),
  660. uint8(123), uint16(123), uint32(123), uint64(123), uint(123),
  661. float32(1.23), float64(1.23),
  662. "abc",
  663. }
  664. for _, v := range tests {
  665. p := NewProperties()
  666. err := p.SetValue("x", v)
  667. assert.Equal(t, err, nil)
  668. assert.Equal(t, p.GetString("x", ""), fmt.Sprintf("%v", v))
  669. }
  670. }
  671. func TestMustSet(t *testing.T) {
  672. input := "key=${key}"
  673. p := mustParse(t, input)
  674. assert.Panic(t, func() { p.MustSet("key", "${key}") }, "circular reference .*")
  675. }
  676. func TestWrite(t *testing.T) {
  677. for _, test := range writeTests {
  678. p, err := parse(test.input)
  679. buf := new(bytes.Buffer)
  680. var n int
  681. switch test.encoding {
  682. case "UTF-8":
  683. n, err = p.Write(buf, UTF8)
  684. case "ISO-8859-1":
  685. n, err = p.Write(buf, ISO_8859_1)
  686. }
  687. assert.Equal(t, err, nil)
  688. s := string(buf.Bytes())
  689. assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
  690. assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
  691. }
  692. }
  693. func TestWriteComment(t *testing.T) {
  694. for _, test := range writeCommentTests {
  695. p, err := parse(test.input)
  696. buf := new(bytes.Buffer)
  697. var n int
  698. switch test.encoding {
  699. case "UTF-8":
  700. n, err = p.WriteComment(buf, "# ", UTF8)
  701. case "ISO-8859-1":
  702. n, err = p.WriteComment(buf, "# ", ISO_8859_1)
  703. }
  704. assert.Equal(t, err, nil)
  705. s := string(buf.Bytes())
  706. assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
  707. assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
  708. }
  709. }
  710. func TestCustomExpansionExpression(t *testing.T) {
  711. testKeyValuePrePostfix(t, "*[", "]*", "key=value\nkey2=*[key]*", "key", "value", "key2", "value")
  712. }
  713. func TestPanicOn32BitIntOverflow(t *testing.T) {
  714. is32Bit = true
  715. var min, max int64 = math.MinInt32 - 1, math.MaxInt32 + 1
  716. input := fmt.Sprintf("min=%d\nmax=%d", min, max)
  717. p := mustParse(t, input)
  718. assert.Equal(t, p.MustGetInt64("min"), min)
  719. assert.Equal(t, p.MustGetInt64("max"), max)
  720. assert.Panic(t, func() { p.MustGetInt("min") }, ".* out of range")
  721. assert.Panic(t, func() { p.MustGetInt("max") }, ".* out of range")
  722. }
  723. func TestPanicOn32BitUintOverflow(t *testing.T) {
  724. is32Bit = true
  725. var max uint64 = math.MaxUint32 + 1
  726. input := fmt.Sprintf("max=%d", max)
  727. p := mustParse(t, input)
  728. assert.Equal(t, p.MustGetUint64("max"), max)
  729. assert.Panic(t, func() { p.MustGetUint("max") }, ".* out of range")
  730. }
  731. func TestDeleteKey(t *testing.T) {
  732. input := "#comments should also be gone\nkey=to-be-deleted\nsecond=key"
  733. p := mustParse(t, input)
  734. assert.Equal(t, len(p.m), 2)
  735. assert.Equal(t, len(p.c), 1)
  736. assert.Equal(t, len(p.k), 2)
  737. p.Delete("key")
  738. assert.Equal(t, len(p.m), 1)
  739. assert.Equal(t, len(p.c), 0)
  740. assert.Equal(t, len(p.k), 1)
  741. assert.Equal(t, p.k[0], "second")
  742. assert.Equal(t, p.m["second"], "key")
  743. }
  744. func TestDeleteUnknownKey(t *testing.T) {
  745. input := "#comments should also be gone\nkey=to-be-deleted"
  746. p := mustParse(t, input)
  747. assert.Equal(t, len(p.m), 1)
  748. assert.Equal(t, len(p.c), 1)
  749. assert.Equal(t, len(p.k), 1)
  750. p.Delete("wrong-key")
  751. assert.Equal(t, len(p.m), 1)
  752. assert.Equal(t, len(p.c), 1)
  753. assert.Equal(t, len(p.k), 1)
  754. }
  755. func TestMerge(t *testing.T) {
  756. input1 := "#comment\nkey=value\nkey2=value2"
  757. input2 := "#another comment\nkey=another value\nkey3=value3"
  758. p1 := mustParse(t, input1)
  759. p2 := mustParse(t, input2)
  760. p1.Merge(p2)
  761. assert.Equal(t, len(p1.m), 3)
  762. assert.Equal(t, len(p1.c), 1)
  763. assert.Equal(t, len(p1.k), 3)
  764. assert.Equal(t, p1.MustGet("key"), "another value")
  765. assert.Equal(t, p1.GetComment("key"), "another comment")
  766. }
  767. func TestMap(t *testing.T) {
  768. input := "key=value\nabc=def"
  769. p := mustParse(t, input)
  770. m := map[string]string{"key": "value", "abc": "def"}
  771. assert.Equal(t, p.Map(), m)
  772. }
  773. func TestFilterFunc(t *testing.T) {
  774. input := "key=value\nabc=def"
  775. p := mustParse(t, input)
  776. pp := p.FilterFunc(func(k, v string) bool {
  777. return k != "abc"
  778. })
  779. m := map[string]string{"key": "value"}
  780. assert.Equal(t, pp.Map(), m)
  781. }
  782. func TestLoad(t *testing.T) {
  783. x := "key=${value}\nvalue=${key}"
  784. p := NewProperties()
  785. p.DisableExpansion = true
  786. err := p.Load([]byte(x), UTF8)
  787. assert.Equal(t, err, nil)
  788. }
  789. // ----------------------------------------------------------------------------
  790. // tests all combinations of delimiters, leading and/or trailing whitespace and newlines.
  791. func testWhitespaceAndDelimiterCombinations(t *testing.T, key, value string) {
  792. whitespace := []string{"", " ", "\f", "\t"}
  793. delimiters := []string{"", " ", "=", ":"}
  794. newlines := []string{"", "\r", "\n", "\r\n"}
  795. for _, dl := range delimiters {
  796. for _, ws1 := range whitespace {
  797. for _, ws2 := range whitespace {
  798. for _, nl := range newlines {
  799. // skip the one case where there is nothing between a key and a value
  800. if ws1 == "" && dl == "" && ws2 == "" && value != "" {
  801. continue
  802. }
  803. input := fmt.Sprintf("%s%s%s%s%s%s", key, ws1, dl, ws2, value, nl)
  804. testKeyValue(t, input, key, value)
  805. }
  806. }
  807. }
  808. }
  809. }
  810. // tests whether key/value pairs exist for a given input.
  811. // keyvalues is expected to be an even number of strings of "key", "value", ...
  812. func testKeyValue(t *testing.T, input string, keyvalues ...string) {
  813. testKeyValuePrePostfix(t, "${", "}", input, keyvalues...)
  814. }
  815. // tests whether key/value pairs exist for a given input.
  816. // keyvalues is expected to be an even number of strings of "key", "value", ...
  817. func testKeyValuePrePostfix(t *testing.T, prefix, postfix, input string, keyvalues ...string) {
  818. p, err := Load([]byte(input), ISO_8859_1)
  819. assert.Equal(t, err, nil)
  820. p.Prefix = prefix
  821. p.Postfix = postfix
  822. assertKeyValues(t, input, p, keyvalues...)
  823. }
  824. // tests whether key/value pairs exist for a given input.
  825. // keyvalues is expected to be an even number of strings of "key", "value", ...
  826. func assertKeyValues(t *testing.T, input string, p *Properties, keyvalues ...string) {
  827. assert.Equal(t, p != nil, true, "want properties")
  828. assert.Equal(t, 2*p.Len(), len(keyvalues), "Odd number of key/value pairs.")
  829. for i := 0; i < len(keyvalues); i += 2 {
  830. key, value := keyvalues[i], keyvalues[i+1]
  831. v, ok := p.Get(key)
  832. if !ok {
  833. t.Errorf("No key %q found (input=%q)", key, input)
  834. }
  835. if got, want := v, value; !reflect.DeepEqual(got, want) {
  836. t.Errorf("Value %q does not match %q (input=%q)", v, value, input)
  837. }
  838. }
  839. }
  840. func mustParse(t *testing.T, s string) *Properties {
  841. p, err := parse(s)
  842. if err != nil {
  843. t.Fatalf("parse failed with %s", err)
  844. }
  845. return p
  846. }
  847. // prints to stderr if the -verbose flag was given.
  848. func printf(format string, args ...interface{}) {
  849. if *verbose {
  850. fmt.Fprintf(os.Stderr, format, args...)
  851. }
  852. }