...

Source file src/gopkg.in/ini.v1/file_test.go

Documentation: gopkg.in/ini.v1

     1  // Copyright 2017 Unknwon
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package ini
    16  
    17  import (
    18  	"bytes"
    19  	"io/ioutil"
    20  	"runtime"
    21  	"sort"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  func TestEmpty(t *testing.T) {
    29  	f := Empty()
    30  	require.NotNil(t, f)
    31  
    32  	// Should only have the default section
    33  	assert.Len(t, f.Sections(), 1)
    34  
    35  	// Default section should not contain any key
    36  	assert.Len(t, f.Section("").Keys(), 0)
    37  }
    38  
    39  func TestFile_NewSection(t *testing.T) {
    40  	f := Empty()
    41  	require.NotNil(t, f)
    42  
    43  	sec, err := f.NewSection("author")
    44  	require.NoError(t, err)
    45  	require.NotNil(t, sec)
    46  	assert.Equal(t, "author", sec.Name())
    47  
    48  	assert.Equal(t, []string{DefaultSection, "author"}, f.SectionStrings())
    49  
    50  	t.Run("with duplicated name", func(t *testing.T) {
    51  		sec, err := f.NewSection("author")
    52  		require.NoError(t, err)
    53  		require.NotNil(t, sec)
    54  
    55  		// Does nothing if section already exists
    56  		assert.Equal(t, []string{DefaultSection, "author"}, f.SectionStrings())
    57  	})
    58  
    59  	t.Run("with empty string", func(t *testing.T) {
    60  		_, err := f.NewSection("")
    61  		require.Error(t, err)
    62  	})
    63  }
    64  
    65  func TestFile_NonUniqueSection(t *testing.T) {
    66  	t.Run("read and write non-unique sections", func(t *testing.T) {
    67  		f, err := LoadSources(LoadOptions{
    68  			AllowNonUniqueSections: true,
    69  		}, []byte(`[Interface]
    70  Address = 192.168.2.1
    71  PrivateKey = <server's privatekey>
    72  ListenPort = 51820
    73  
    74  [Peer]
    75  PublicKey = <client's publickey>
    76  AllowedIPs = 192.168.2.2/32
    77  
    78  [Peer]
    79  PublicKey = <client2's publickey>
    80  AllowedIPs = 192.168.2.3/32`))
    81  		require.NoError(t, err)
    82  		require.NotNil(t, f)
    83  
    84  		sec, err := f.NewSection("Peer")
    85  		require.NoError(t, err)
    86  		require.NotNil(t, f)
    87  
    88  		_, _ = sec.NewKey("PublicKey", "<client3's publickey>")
    89  		_, _ = sec.NewKey("AllowedIPs", "192.168.2.4/32")
    90  
    91  		var buf bytes.Buffer
    92  		_, err = f.WriteTo(&buf)
    93  		require.NoError(t, err)
    94  		str := buf.String()
    95  		assert.Equal(t, `[Interface]
    96  Address    = 192.168.2.1
    97  PrivateKey = <server's privatekey>
    98  ListenPort = 51820
    99  
   100  [Peer]
   101  PublicKey  = <client's publickey>
   102  AllowedIPs = 192.168.2.2/32
   103  
   104  [Peer]
   105  PublicKey  = <client2's publickey>
   106  AllowedIPs = 192.168.2.3/32
   107  
   108  [Peer]
   109  PublicKey  = <client3's publickey>
   110  AllowedIPs = 192.168.2.4/32
   111  `, str)
   112  	})
   113  
   114  	t.Run("delete non-unique section", func(t *testing.T) {
   115  		f, err := LoadSources(LoadOptions{
   116  			AllowNonUniqueSections: true,
   117  		}, []byte(`[Interface]
   118  Address    = 192.168.2.1
   119  PrivateKey = <server's privatekey>
   120  ListenPort = 51820
   121  
   122  [Peer]
   123  PublicKey  = <client's publickey>
   124  AllowedIPs = 192.168.2.2/32
   125  
   126  [Peer]
   127  PublicKey  = <client2's publickey>
   128  AllowedIPs = 192.168.2.3/32
   129  
   130  [Peer]
   131  PublicKey  = <client3's publickey>
   132  AllowedIPs = 192.168.2.4/32
   133  
   134  `))
   135  		require.NoError(t, err)
   136  		require.NotNil(t, f)
   137  
   138  		err = f.DeleteSectionWithIndex("Peer", 1)
   139  		require.NoError(t, err)
   140  
   141  		var buf bytes.Buffer
   142  		_, err = f.WriteTo(&buf)
   143  		require.NoError(t, err)
   144  		str := buf.String()
   145  		assert.Equal(t, `[Interface]
   146  Address    = 192.168.2.1
   147  PrivateKey = <server's privatekey>
   148  ListenPort = 51820
   149  
   150  [Peer]
   151  PublicKey  = <client's publickey>
   152  AllowedIPs = 192.168.2.2/32
   153  
   154  [Peer]
   155  PublicKey  = <client3's publickey>
   156  AllowedIPs = 192.168.2.4/32
   157  `, str)
   158  	})
   159  
   160  	t.Run("delete all sections", func(t *testing.T) {
   161  		f := Empty(LoadOptions{
   162  			AllowNonUniqueSections: true,
   163  		})
   164  		require.NotNil(t, f)
   165  
   166  		_ = f.NewSections("Interface", "Peer", "Peer")
   167  		assert.Equal(t, []string{DefaultSection, "Interface", "Peer", "Peer"}, f.SectionStrings())
   168  		f.DeleteSection("Peer")
   169  		assert.Equal(t, []string{DefaultSection, "Interface"}, f.SectionStrings())
   170  	})
   171  }
   172  
   173  func TestFile_NewRawSection(t *testing.T) {
   174  	f := Empty()
   175  	require.NotNil(t, f)
   176  
   177  	sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000
   178  111111111111111111100000000000111000000000`)
   179  	require.NoError(t, err)
   180  	require.NotNil(t, sec)
   181  	assert.Equal(t, "comments", sec.Name())
   182  
   183  	assert.Equal(t, []string{DefaultSection, "comments"}, f.SectionStrings())
   184  	assert.Equal(t, `1111111111111111111000000000000000001110000
   185  111111111111111111100000000000111000000000`, f.Section("comments").Body())
   186  
   187  	t.Run("with duplicated name", func(t *testing.T) {
   188  		sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000`)
   189  		require.NoError(t, err)
   190  		require.NotNil(t, sec)
   191  		assert.Equal(t, []string{DefaultSection, "comments"}, f.SectionStrings())
   192  
   193  		// Overwrite previous existed section
   194  		assert.Equal(t, `1111111111111111111000000000000000001110000`, f.Section("comments").Body())
   195  	})
   196  
   197  	t.Run("with empty string", func(t *testing.T) {
   198  		_, err := f.NewRawSection("", "")
   199  		require.Error(t, err)
   200  	})
   201  }
   202  
   203  func TestFile_NewSections(t *testing.T) {
   204  	f := Empty()
   205  	require.NotNil(t, f)
   206  
   207  	assert.NoError(t, f.NewSections("package", "author"))
   208  	assert.Equal(t, []string{DefaultSection, "package", "author"}, f.SectionStrings())
   209  
   210  	t.Run("with duplicated name", func(t *testing.T) {
   211  		assert.NoError(t, f.NewSections("author", "features"))
   212  
   213  		// Ignore section already exists
   214  		assert.Equal(t, []string{DefaultSection, "package", "author", "features"}, f.SectionStrings())
   215  	})
   216  
   217  	t.Run("with empty string", func(t *testing.T) {
   218  		assert.Error(t, f.NewSections("", ""))
   219  	})
   220  }
   221  
   222  func TestFile_GetSection(t *testing.T) {
   223  	f, err := Load(fullConf)
   224  	require.NoError(t, err)
   225  	require.NotNil(t, f)
   226  
   227  	sec, err := f.GetSection("author")
   228  	require.NoError(t, err)
   229  	require.NotNil(t, sec)
   230  	assert.Equal(t, "author", sec.Name())
   231  
   232  	t.Run("section not exists", func(t *testing.T) {
   233  		_, err := f.GetSection("404")
   234  		require.Error(t, err)
   235  	})
   236  }
   237  
   238  func TestFile_HasSection(t *testing.T) {
   239  	f, err := Load(fullConf)
   240  	require.NoError(t, err)
   241  	require.NotNil(t, f)
   242  
   243  	sec := f.HasSection("author")
   244  	assert.True(t, sec)
   245  
   246  	t.Run("section not exists", func(t *testing.T) {
   247  		nonexistent := f.HasSection("404")
   248  		assert.False(t, nonexistent)
   249  	})
   250  }
   251  
   252  func TestFile_Section(t *testing.T) {
   253  	t.Run("get a section", func(t *testing.T) {
   254  		f, err := Load(fullConf)
   255  		require.NoError(t, err)
   256  		require.NotNil(t, f)
   257  
   258  		sec := f.Section("author")
   259  		require.NotNil(t, sec)
   260  		assert.Equal(t, "author", sec.Name())
   261  
   262  		t.Run("section not exists", func(t *testing.T) {
   263  			sec := f.Section("404")
   264  			require.NotNil(t, sec)
   265  			assert.Equal(t, "404", sec.Name())
   266  		})
   267  	})
   268  
   269  	t.Run("get default section in lower case with insensitive load", func(t *testing.T) {
   270  		f, err := InsensitiveLoad([]byte(`
   271  [default]
   272  NAME = ini
   273  VERSION = v1`))
   274  		require.NoError(t, err)
   275  		require.NotNil(t, f)
   276  
   277  		assert.Equal(t, "ini", f.Section("").Key("name").String())
   278  		assert.Equal(t, "v1", f.Section("").Key("version").String())
   279  	})
   280  
   281  	t.Run("get sections after deletion", func(t *testing.T) {
   282  		f, err := Load([]byte(`
   283  [RANDOM]
   284  `))
   285  		require.NoError(t, err)
   286  		require.NotNil(t, f)
   287  
   288  		sectionNames := f.SectionStrings()
   289  		sort.Strings(sectionNames)
   290  		assert.Equal(t, []string{DefaultSection, "RANDOM"}, sectionNames)
   291  
   292  		for _, currentSection := range sectionNames {
   293  			f.DeleteSection(currentSection)
   294  		}
   295  
   296  		for sectionParam, expectedSectionName := range map[string]string{
   297  			"":       DefaultSection,
   298  			"RANDOM": "RANDOM",
   299  		} {
   300  			sec := f.Section(sectionParam)
   301  			require.NotNil(t, sec)
   302  			assert.Equal(t, expectedSectionName, sec.Name())
   303  		}
   304  	})
   305  
   306  }
   307  
   308  func TestFile_Sections(t *testing.T) {
   309  	f, err := Load(fullConf)
   310  	require.NoError(t, err)
   311  	require.NotNil(t, f)
   312  
   313  	secs := f.Sections()
   314  	names := []string{DefaultSection, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"}
   315  	assert.Len(t, secs, len(names))
   316  	for i, name := range names {
   317  		assert.Equal(t, name, secs[i].Name())
   318  	}
   319  }
   320  
   321  func TestFile_ChildSections(t *testing.T) {
   322  	f, err := Load([]byte(`
   323  [node]
   324  [node.biz1]
   325  [node.biz2]
   326  [node.biz3]
   327  [node.bizN]
   328  `))
   329  	require.NoError(t, err)
   330  	require.NotNil(t, f)
   331  
   332  	children := f.ChildSections("node")
   333  	names := []string{"node.biz1", "node.biz2", "node.biz3", "node.bizN"}
   334  	assert.Len(t, children, len(names))
   335  	for i, name := range names {
   336  		assert.Equal(t, name, children[i].Name())
   337  	}
   338  }
   339  
   340  func TestFile_SectionStrings(t *testing.T) {
   341  	f, err := Load(fullConf)
   342  	require.NoError(t, err)
   343  	require.NotNil(t, f)
   344  
   345  	assert.Equal(t, []string{DefaultSection, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"}, f.SectionStrings())
   346  }
   347  
   348  func TestFile_DeleteSection(t *testing.T) {
   349  	t.Run("delete a section", func(t *testing.T) {
   350  		f := Empty()
   351  		require.NotNil(t, f)
   352  
   353  		_ = f.NewSections("author", "package", "features")
   354  		f.DeleteSection("features")
   355  		f.DeleteSection("")
   356  		assert.Equal(t, []string{"author", "package"}, f.SectionStrings())
   357  	})
   358  
   359  	t.Run("delete default section", func(t *testing.T) {
   360  		f := Empty()
   361  		require.NotNil(t, f)
   362  
   363  		f.Section("").Key("foo").SetValue("bar")
   364  		f.Section("section1").Key("key1").SetValue("value1")
   365  		f.DeleteSection("")
   366  		assert.Equal(t, []string{"section1"}, f.SectionStrings())
   367  
   368  		var buf bytes.Buffer
   369  		_, err := f.WriteTo(&buf)
   370  		require.NoError(t, err)
   371  
   372  		assert.Equal(t, `[section1]
   373  key1 = value1
   374  `, buf.String())
   375  	})
   376  
   377  	t.Run("delete a section with InsensitiveSections", func(t *testing.T) {
   378  		f := Empty(LoadOptions{InsensitiveSections: true})
   379  		require.NotNil(t, f)
   380  
   381  		_ = f.NewSections("author", "package", "features")
   382  		f.DeleteSection("FEATURES")
   383  		f.DeleteSection("")
   384  		assert.Equal(t, []string{"author", "package"}, f.SectionStrings())
   385  	})
   386  }
   387  
   388  func TestFile_Append(t *testing.T) {
   389  	f := Empty()
   390  	require.NotNil(t, f)
   391  
   392  	assert.NoError(t, f.Append(minimalConf, []byte(`
   393  [author]
   394  NAME = Unknwon`)))
   395  
   396  	t.Run("with bad input", func(t *testing.T) {
   397  		assert.Error(t, f.Append(123))
   398  		assert.Error(t, f.Append(minimalConf, 123))
   399  	})
   400  }
   401  
   402  func TestFile_WriteTo(t *testing.T) {
   403  	if runtime.GOOS == "windows" {
   404  		t.Skip("Skipping testing on Windows")
   405  	}
   406  
   407  	t.Run("write content to somewhere", func(t *testing.T) {
   408  		f, err := Load(fullConf)
   409  		require.NoError(t, err)
   410  		require.NotNil(t, f)
   411  
   412  		f.Section("author").Comment = `Information about package author
   413  # Bio can be written in multiple lines.`
   414  		f.Section("author").Key("NAME").Comment = "This is author name"
   415  		_, _ = f.Section("note").NewBooleanKey("boolean_key")
   416  		_, _ = f.Section("note").NewKey("more", "notes")
   417  
   418  		var buf bytes.Buffer
   419  		_, err = f.WriteTo(&buf)
   420  		require.NoError(t, err)
   421  
   422  		golden := "testdata/TestFile_WriteTo.golden"
   423  		if *update {
   424  			require.NoError(t, ioutil.WriteFile(golden, buf.Bytes(), 0644))
   425  		}
   426  
   427  		expected, err := ioutil.ReadFile(golden)
   428  		require.NoError(t, err)
   429  		assert.Equal(t, string(expected), buf.String())
   430  	})
   431  
   432  	t.Run("support multiline comments", func(t *testing.T) {
   433  		f, err := Load([]byte(`
   434  # 
   435  # general.domain
   436  # 
   437  # Domain name of XX system.
   438  domain      = mydomain.com
   439  `))
   440  		require.NoError(t, err)
   441  
   442  		f.Section("").Key("test").Comment = "Multiline\nComment"
   443  
   444  		var buf bytes.Buffer
   445  		_, err = f.WriteTo(&buf)
   446  		require.NoError(t, err)
   447  
   448  		assert.Equal(t, `# 
   449  # general.domain
   450  # 
   451  # Domain name of XX system.
   452  domain = mydomain.com
   453  ; Multiline
   454  ; Comment
   455  test   = 
   456  `, buf.String())
   457  
   458  	})
   459  
   460  	t.Run("keep leading and trailing spaces in value", func(t *testing.T) {
   461  		f, _ := Load([]byte(`[foo]
   462  bar1 = '  val ue1 '
   463  bar2 = """  val ue2 """
   464  bar3 = "  val ue3 "
   465  `))
   466  		require.NotNil(t, f)
   467  
   468  		var buf bytes.Buffer
   469  		_, err := f.WriteTo(&buf)
   470  		require.NoError(t, err)
   471  		assert.Equal(t, `[foo]
   472  bar1 = "  val ue1 "
   473  bar2 = "  val ue2 "
   474  bar3 = "  val ue3 "
   475  `, buf.String())
   476  	})
   477  }
   478  
   479  func TestFile_SaveTo(t *testing.T) {
   480  	f, err := Load(fullConf)
   481  	require.NoError(t, err)
   482  	require.NotNil(t, f)
   483  
   484  	assert.NoError(t, f.SaveTo("testdata/conf_out.ini"))
   485  	assert.NoError(t, f.SaveToIndent("testdata/conf_out.ini", "\t"))
   486  }
   487  
   488  func TestFile_WriteToWithOutputDelimiter(t *testing.T) {
   489  	f, err := LoadSources(LoadOptions{
   490  		KeyValueDelimiterOnWrite: "->",
   491  	}, []byte(`[Others]
   492  Cities = HangZhou|Boston
   493  Visits = 1993-10-07T20:17:05Z, 1993-10-07T20:17:05Z
   494  Years = 1993,1994
   495  Numbers = 10010,10086
   496  Ages = 18,19
   497  Populations = 12345678,98765432
   498  Coordinates = 192.168,10.11
   499  Flags       = true,false
   500  Note = Hello world!`))
   501  	require.NoError(t, err)
   502  	require.NotNil(t, f)
   503  
   504  	var actual bytes.Buffer
   505  	var expected = []byte(`[Others]
   506  Cities      -> HangZhou|Boston
   507  Visits      -> 1993-10-07T20:17:05Z, 1993-10-07T20:17:05Z
   508  Years       -> 1993,1994
   509  Numbers     -> 10010,10086
   510  Ages        -> 18,19
   511  Populations -> 12345678,98765432
   512  Coordinates -> 192.168,10.11
   513  Flags       -> true,false
   514  Note        -> Hello world!
   515  `)
   516  	_, err = f.WriteTo(&actual)
   517  	require.NoError(t, err)
   518  
   519  	assert.Equal(t, expected, actual.Bytes())
   520  }
   521  
   522  // Inspired by https://github.com/go-ini/ini/issues/207
   523  func TestReloadAfterShadowLoad(t *testing.T) {
   524  	f, err := ShadowLoad([]byte(`
   525  [slice]
   526  v = 1
   527  v = 2
   528  v = 3
   529  `))
   530  	require.NoError(t, err)
   531  	require.NotNil(t, f)
   532  
   533  	assert.Equal(t, []string{"1", "2", "3"}, f.Section("slice").Key("v").ValueWithShadows())
   534  
   535  	require.NoError(t, f.Reload())
   536  	assert.Equal(t, []string{"1", "2", "3"}, f.Section("slice").Key("v").ValueWithShadows())
   537  }
   538  

View as plain text