...

Source file src/github.com/magiconair/properties/properties_test.go

Documentation: github.com/magiconair/properties

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

View as plain text