代码拉取完成,页面将自动刷新
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package ini
import (
"bytes"
"fmt"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type testNested struct {
Cities []string `delim:"|"`
Visits []time.Time
Years []int
Numbers []int64
Ages []uint
Populations []uint64
Coordinates []float64
Flags []bool
Note string
Unused int `ini:"-"`
}
type TestEmbeded struct {
GPA float64
}
type testStruct struct {
Name string `ini:"NAME"`
Age int
Male bool
Money float64
Born time.Time
Time time.Duration `ini:"Duration"`
OldVersionTime time.Duration
Others testNested
OthersPtr *testNested
NilPtr *testNested
*TestEmbeded `ini:"grade"`
Unused int `ini:"-"`
Unsigned uint
Omitted bool `ini:"omitthis,omitempty"`
Shadows []string `ini:",allowshadow"`
ShadowInts []int `ini:"Shadows,allowshadow"`
BoolPtr *bool
BoolPtrNil *bool
FloatPtr *float64
FloatPtrNil *float64
IntPtr *int
IntPtrNil *int
UintPtr *uint
UintPtrNil *uint
StringPtr *string
StringPtrNil *string
TimePtr *time.Time
TimePtrNil *time.Time
DurationPtr *time.Duration
DurationPtrNil *time.Duration
}
type testInterface struct {
Address string
ListenPort int
PrivateKey string
}
type testPeer struct {
PublicKey string
PresharedKey string
AllowedIPs []string `delim:","`
}
type testNonUniqueSectionsStruct struct {
Interface testInterface
Peer []testPeer `ini:",nonunique"`
}
type BaseStruct struct {
Base bool
}
type testExtend struct {
BaseStruct `ini:",extends"`
Extend bool
}
const confDataStruct = `
NAME = Unknwon
Age = 21
Male = true
Money = 1.25
Born = 1993-10-07T20:17:05Z
Duration = 2h45m
OldVersionTime = 30
Unsigned = 3
omitthis = true
Shadows = 1, 2
Shadows = 3, 4
BoolPtr = false
FloatPtr = 0
IntPtr = 0
UintPtr = 0
StringPtr = ""
TimePtr = 0001-01-01T00:00:00Z
DurationPtr = 0s
[Others]
Cities = HangZhou|Boston
Visits = 1993-10-07T20:17:05Z, 1993-10-07T20:17:05Z
Years = 1993,1994
Numbers = 10010,10086
Ages = 18,19
Populations = 12345678,98765432
Coordinates = 192.168,10.11
Flags = true,false
Note = Hello world!
[OthersPtr]
Cities = HangZhou|Boston
Visits = 1993-10-07T20:17:05Z, 1993-10-07T20:17:05Z
Years = 1993,1994
Numbers = 10010,10086
Ages = 18,19
Populations = 12345678,98765432
Coordinates = 192.168,10.11
Flags = true,false
Note = Hello world!
[grade]
GPA = 2.8
[foo.bar]
Here = there
When = then
[extended]
Base = true
Extend = true
`
const confNonUniqueSectionDataStruct = `[Interface]
Address = 10.2.0.1/24
ListenPort = 34777
PrivateKey = privServerKey
[Peer]
PublicKey = pubClientKey
PresharedKey = psKey
AllowedIPs = 10.2.0.2/32,fd00:2::2/128
[Peer]
PublicKey = pubClientKey2
PresharedKey = psKey2
AllowedIPs = 10.2.0.3/32,fd00:2::3/128
`
type unsupport struct {
Byte byte
}
type unsupport2 struct {
Others struct {
Cities byte
}
}
type Unsupport3 struct {
Cities byte
}
type unsupport4 struct {
*Unsupport3 `ini:"Others"`
}
type defaultValue struct {
Name string
Age int
Male bool
Optional *bool
Money float64
Born time.Time
Cities []string
}
type fooBar struct {
Here, When string
}
const invalidDataConfStruct = `
Name =
Age = age
Male = 123
Money = money
Born = nil
Cities =
`
func Test_MapToStruct(t *testing.T) {
t.Run("map to struct", func(t *testing.T) {
t.Run("map file to struct", func(t *testing.T) {
ts := new(testStruct)
assert.NoError(t, MapTo(ts, []byte(confDataStruct)))
assert.Equal(t, "Unknwon", ts.Name)
assert.Equal(t, 21, ts.Age)
assert.True(t, ts.Male)
assert.Equal(t, 1.25, ts.Money)
assert.Equal(t, uint(3), ts.Unsigned)
ti, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
require.NoError(t, err)
assert.Equal(t, ti.String(), ts.Born.String())
dur, err := time.ParseDuration("2h45m")
require.NoError(t, err)
assert.Equal(t, dur.Seconds(), ts.Time.Seconds())
assert.Equal(t, 30*time.Second, ts.OldVersionTime*time.Second)
assert.Equal(t, "HangZhou,Boston", strings.Join(ts.Others.Cities, ","))
assert.Equal(t, ti.String(), ts.Others.Visits[0].String())
assert.Equal(t, "[1993 1994]", fmt.Sprint(ts.Others.Years))
assert.Equal(t, "[10010 10086]", fmt.Sprint(ts.Others.Numbers))
assert.Equal(t, "[18 19]", fmt.Sprint(ts.Others.Ages))
assert.Equal(t, "[12345678 98765432]", fmt.Sprint(ts.Others.Populations))
assert.Equal(t, "[192.168 10.11]", fmt.Sprint(ts.Others.Coordinates))
assert.Equal(t, "[true false]", fmt.Sprint(ts.Others.Flags))
assert.Equal(t, "Hello world!", ts.Others.Note)
assert.Equal(t, 2.8, ts.TestEmbeded.GPA)
assert.Equal(t, "HangZhou,Boston", strings.Join(ts.OthersPtr.Cities, ","))
assert.Equal(t, ti.String(), ts.OthersPtr.Visits[0].String())
assert.Equal(t, "[1993 1994]", fmt.Sprint(ts.OthersPtr.Years))
assert.Equal(t, "[10010 10086]", fmt.Sprint(ts.OthersPtr.Numbers))
assert.Equal(t, "[18 19]", fmt.Sprint(ts.OthersPtr.Ages))
assert.Equal(t, "[12345678 98765432]", fmt.Sprint(ts.OthersPtr.Populations))
assert.Equal(t, "[192.168 10.11]", fmt.Sprint(ts.OthersPtr.Coordinates))
assert.Equal(t, "[true false]", fmt.Sprint(ts.OthersPtr.Flags))
assert.Equal(t, "Hello world!", ts.OthersPtr.Note)
assert.Nil(t, ts.NilPtr)
assert.Equal(t, false, *ts.BoolPtr)
assert.Nil(t, ts.BoolPtrNil)
assert.Equal(t, float64(0), *ts.FloatPtr)
assert.Nil(t, ts.FloatPtrNil)
assert.Equal(t, 0, *ts.IntPtr)
assert.Nil(t, ts.IntPtrNil)
assert.Equal(t, uint(0), *ts.UintPtr)
assert.Nil(t, ts.UintPtrNil)
assert.Equal(t, "", *ts.StringPtr)
assert.Nil(t, ts.StringPtrNil)
assert.NotNil(t, *ts.TimePtr)
assert.Nil(t, ts.TimePtrNil)
assert.Equal(t, time.Duration(0), *ts.DurationPtr)
assert.Nil(t, ts.DurationPtrNil)
})
t.Run("map section to struct", func(t *testing.T) {
foobar := new(fooBar)
f, err := Load([]byte(confDataStruct))
require.NoError(t, err)
assert.NoError(t, f.Section("foo.bar").MapTo(foobar))
assert.Equal(t, "there", foobar.Here)
assert.Equal(t, "then", foobar.When)
})
t.Run("map to non-pointer struct", func(t *testing.T) {
f, err := Load([]byte(confDataStruct))
require.NoError(t, err)
require.NotNil(t, f)
assert.Error(t, f.MapTo(testStruct{}))
})
t.Run("map to unsupported type", func(t *testing.T) {
f, err := Load([]byte(confDataStruct))
require.NoError(t, err)
require.NotNil(t, f)
f.NameMapper = func(raw string) string {
if raw == "Byte" {
return "NAME"
}
return raw
}
assert.Error(t, f.MapTo(&unsupport{}))
assert.Error(t, f.MapTo(&unsupport2{}))
assert.Error(t, f.MapTo(&unsupport4{}))
})
t.Run("map to omitempty field", func(t *testing.T) {
ts := new(testStruct)
assert.NoError(t, MapTo(ts, []byte(confDataStruct)))
assert.Equal(t, true, ts.Omitted)
})
t.Run("map with shadows", func(t *testing.T) {
f, err := LoadSources(LoadOptions{AllowShadows: true}, []byte(confDataStruct))
require.NoError(t, err)
ts := new(testStruct)
assert.NoError(t, f.MapTo(ts))
assert.Equal(t, "1 2 3 4", strings.Join(ts.Shadows, " "))
assert.Equal(t, "[1 2 3 4]", fmt.Sprintf("%v", ts.ShadowInts))
})
t.Run("map from invalid data source", func(t *testing.T) {
assert.Error(t, MapTo(&testStruct{}, "hi"))
})
t.Run("map to wrong types and gain default values", func(t *testing.T) {
f, err := Load([]byte(invalidDataConfStruct))
require.NoError(t, err)
ti, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
require.NoError(t, err)
dv := &defaultValue{"Joe", 10, true, nil, 1.25, ti, []string{"HangZhou", "Boston"}}
assert.NoError(t, f.MapTo(dv))
assert.Equal(t, "Joe", dv.Name)
assert.Equal(t, 10, dv.Age)
assert.True(t, dv.Male)
assert.Equal(t, 1.25, dv.Money)
assert.Equal(t, ti.String(), dv.Born.String())
assert.Equal(t, "HangZhou,Boston", strings.Join(dv.Cities, ","))
})
t.Run("map to extended base", func(t *testing.T) {
f, err := Load([]byte(confDataStruct))
require.NoError(t, err)
require.NotNil(t, f)
te := testExtend{}
assert.NoError(t, f.Section("extended").MapTo(&te))
assert.True(t, te.Base)
assert.True(t, te.Extend)
})
})
t.Run("map to struct in strict mode", func(t *testing.T) {
f, err := Load([]byte(`
name=bruce
age=a30`))
require.NoError(t, err)
type Strict struct {
Name string `ini:"name"`
Age int `ini:"age"`
}
s := new(Strict)
assert.Error(t, f.Section("").StrictMapTo(s))
})
t.Run("map slice in strict mode", func(t *testing.T) {
f, err := Load([]byte(`
names=alice, bruce`))
require.NoError(t, err)
type Strict struct {
Names []string `ini:"names"`
}
s := new(Strict)
assert.NoError(t, f.Section("").StrictMapTo(s))
assert.Equal(t, "[alice bruce]", fmt.Sprint(s.Names))
})
}
func Test_MapToStructNonUniqueSections(t *testing.T) {
t.Run("map to struct non unique", func(t *testing.T) {
t.Run("map file to struct non unique", func(t *testing.T) {
f, err := LoadSources(LoadOptions{AllowNonUniqueSections: true}, []byte(confNonUniqueSectionDataStruct))
require.NoError(t, err)
ts := new(testNonUniqueSectionsStruct)
assert.NoError(t, f.MapTo(ts))
assert.Equal(t, "10.2.0.1/24", ts.Interface.Address)
assert.Equal(t, 34777, ts.Interface.ListenPort)
assert.Equal(t, "privServerKey", ts.Interface.PrivateKey)
assert.Equal(t, "pubClientKey", ts.Peer[0].PublicKey)
assert.Equal(t, "psKey", ts.Peer[0].PresharedKey)
assert.Equal(t, "10.2.0.2/32", ts.Peer[0].AllowedIPs[0])
assert.Equal(t, "fd00:2::2/128", ts.Peer[0].AllowedIPs[1])
assert.Equal(t, "pubClientKey2", ts.Peer[1].PublicKey)
assert.Equal(t, "psKey2", ts.Peer[1].PresharedKey)
assert.Equal(t, "10.2.0.3/32", ts.Peer[1].AllowedIPs[0])
assert.Equal(t, "fd00:2::3/128", ts.Peer[1].AllowedIPs[1])
})
t.Run("map non unique section to struct", func(t *testing.T) {
newPeer := new(testPeer)
newPeerSlice := make([]testPeer, 0)
f, err := LoadSources(LoadOptions{AllowNonUniqueSections: true}, []byte(confNonUniqueSectionDataStruct))
require.NoError(t, err)
// try only first one
assert.NoError(t, f.Section("Peer").MapTo(newPeer))
assert.Equal(t, "pubClientKey", newPeer.PublicKey)
assert.Equal(t, "psKey", newPeer.PresharedKey)
assert.Equal(t, "10.2.0.2/32", newPeer.AllowedIPs[0])
assert.Equal(t, "fd00:2::2/128", newPeer.AllowedIPs[1])
// try all
assert.NoError(t, f.Section("Peer").MapTo(&newPeerSlice))
assert.Equal(t, "pubClientKey", newPeerSlice[0].PublicKey)
assert.Equal(t, "psKey", newPeerSlice[0].PresharedKey)
assert.Equal(t, "10.2.0.2/32", newPeerSlice[0].AllowedIPs[0])
assert.Equal(t, "fd00:2::2/128", newPeerSlice[0].AllowedIPs[1])
assert.Equal(t, "pubClientKey2", newPeerSlice[1].PublicKey)
assert.Equal(t, "psKey2", newPeerSlice[1].PresharedKey)
assert.Equal(t, "10.2.0.3/32", newPeerSlice[1].AllowedIPs[0])
assert.Equal(t, "fd00:2::3/128", newPeerSlice[1].AllowedIPs[1])
})
t.Run("map non unique sections with subsections to struct", func(t *testing.T) {
iniFile, err := LoadSources(LoadOptions{AllowNonUniqueSections: true}, strings.NewReader(`
[Section]
FieldInSubSection = 1
FieldInSubSection2 = 2
FieldInSection = 3
[Section]
FieldInSubSection = 4
FieldInSubSection2 = 5
FieldInSection = 6
`))
require.NoError(t, err)
type SubSection struct {
FieldInSubSection string `ini:"FieldInSubSection"`
}
type SubSection2 struct {
FieldInSubSection2 string `ini:"FieldInSubSection2"`
}
type Section struct {
SubSection `ini:"Section"`
SubSection2 `ini:"Section"`
FieldInSection string `ini:"FieldInSection"`
}
type File struct {
Sections []Section `ini:"Section,nonunique"`
}
f := new(File)
err = iniFile.MapTo(f)
require.NoError(t, err)
assert.Equal(t, "1", f.Sections[0].FieldInSubSection)
assert.Equal(t, "2", f.Sections[0].FieldInSubSection2)
assert.Equal(t, "3", f.Sections[0].FieldInSection)
assert.Equal(t, "4", f.Sections[1].FieldInSubSection)
assert.Equal(t, "5", f.Sections[1].FieldInSubSection2)
assert.Equal(t, "6", f.Sections[1].FieldInSection)
})
})
}
func Test_ReflectFromStruct(t *testing.T) {
t.Run("reflect from struct", func(t *testing.T) {
type Embeded struct {
Dates []time.Time `delim:"|" comment:"Time data"`
Places []string
Years []int
Numbers []int64
Ages []uint
Populations []uint64
Coordinates []float64
Flags []bool
None []int
}
type Author struct {
Name string `ini:"NAME"`
Male bool
Optional *bool
Age int `comment:"Author's age"`
Height uint
GPA float64
Date time.Time
NeverMind string `ini:"-"`
ignored string
*Embeded `ini:"infos" comment:"Embeded section"`
}
ti, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
require.NoError(t, err)
a := &Author{"Unknwon", true, nil, 21, 100, 2.8, ti, "", "ignored",
&Embeded{
[]time.Time{ti, ti},
[]string{"HangZhou", "Boston"},
[]int{1993, 1994},
[]int64{10010, 10086},
[]uint{18, 19},
[]uint64{12345678, 98765432},
[]float64{192.168, 10.11},
[]bool{true, false},
[]int{},
}}
cfg := Empty()
assert.NoError(t, ReflectFrom(cfg, a))
var buf bytes.Buffer
_, err = cfg.WriteTo(&buf)
require.NoError(t, err)
assert.Equal(t, `NAME = Unknwon
Male = true
Optional =
; Author's age
Age = 21
Height = 100
GPA = 2.8
Date = 1993-10-07T20:17:05Z
; Embeded section
[infos]
; Time data
Dates = 1993-10-07T20:17:05Z|1993-10-07T20:17:05Z
Places = HangZhou,Boston
Years = 1993,1994
Numbers = 10010,10086
Ages = 18,19
Populations = 12345678,98765432
Coordinates = 192.168,10.11
Flags = true,false
None =
`,
buf.String(),
)
t.Run("reflect from non-point struct", func(t *testing.T) {
assert.Error(t, ReflectFrom(cfg, Author{}))
})
t.Run("reflect from struct with omitempty", func(t *testing.T) {
cfg := Empty()
type SpecialStruct struct {
FirstName string `ini:"first_name"`
LastName string `ini:"last_name,omitempty"`
JustOmitMe string `ini:"omitempty"`
LastLogin time.Time `ini:"last_login,omitempty"`
LastLogin2 time.Time `ini:",omitempty"`
NotEmpty int `ini:"omitempty"`
Number int64 `ini:",omitempty"`
Ages uint `ini:",omitempty"`
Population uint64 `ini:",omitempty"`
Coordinate float64 `ini:",omitempty"`
Flag bool `ini:",omitempty"`
Note *string `ini:",omitempty"`
}
special := &SpecialStruct{
FirstName: "John",
LastName: "Doe",
NotEmpty: 9,
}
assert.NoError(t, ReflectFrom(cfg, special))
var buf bytes.Buffer
_, err = cfg.WriteTo(&buf)
assert.Equal(t, `first_name = John
last_name = Doe
omitempty = 9
`,
buf.String(),
)
})
t.Run("reflect from struct with non-anonymous structure pointer", func(t *testing.T) {
cfg := Empty()
type Rpc struct {
Enable bool `ini:"enable"`
Type string `ini:"type"`
Address string `ini:"addr"`
Name string `ini:"name"`
}
type Cfg struct {
Rpc *Rpc `ini:"rpc"`
}
config := &Cfg{
Rpc: &Rpc{
Enable: true,
Type: "type",
Address: "address",
Name: "name",
},
}
assert.NoError(t, cfg.ReflectFrom(config))
var buf bytes.Buffer
_, err = cfg.WriteTo(&buf)
assert.Equal(t, `[rpc]
enable = true
type = type
addr = address
name = name
`,
buf.String(),
)
})
})
}
func Test_ReflectFromStructNonUniqueSections(t *testing.T) {
t.Run("reflect from struct with non unique sections", func(t *testing.T) {
nonUnique := &testNonUniqueSectionsStruct{
Interface: testInterface{
Address: "10.2.0.1/24",
ListenPort: 34777,
PrivateKey: "privServerKey",
},
Peer: []testPeer{
{
PublicKey: "pubClientKey",
PresharedKey: "psKey",
AllowedIPs: []string{"10.2.0.2/32,fd00:2::2/128"},
},
{
PublicKey: "pubClientKey2",
PresharedKey: "psKey2",
AllowedIPs: []string{"10.2.0.3/32,fd00:2::3/128"},
},
},
}
cfg := Empty(LoadOptions{
AllowNonUniqueSections: true,
})
assert.NoError(t, ReflectFrom(cfg, nonUnique))
var buf bytes.Buffer
_, err := cfg.WriteTo(&buf)
require.NoError(t, err)
assert.Equal(t, confNonUniqueSectionDataStruct, buf.String())
// note: using ReflectFrom from should overwrite the existing sections
err = cfg.Section("Peer").ReflectFrom([]*testPeer{
{
PublicKey: "pubClientKey3",
PresharedKey: "psKey3",
AllowedIPs: []string{"10.2.0.4/32,fd00:2::4/128"},
},
{
PublicKey: "pubClientKey4",
PresharedKey: "psKey4",
AllowedIPs: []string{"10.2.0.5/32,fd00:2::5/128"},
},
})
require.NoError(t, err)
buf = bytes.Buffer{}
_, err = cfg.WriteTo(&buf)
require.NoError(t, err)
assert.Equal(t, `[Interface]
Address = 10.2.0.1/24
ListenPort = 34777
PrivateKey = privServerKey
[Peer]
PublicKey = pubClientKey3
PresharedKey = psKey3
AllowedIPs = 10.2.0.4/32,fd00:2::4/128
[Peer]
PublicKey = pubClientKey4
PresharedKey = psKey4
AllowedIPs = 10.2.0.5/32,fd00:2::5/128
`,
buf.String(),
)
// note: using ReflectFrom from should overwrite the existing sections
err = cfg.Section("Peer").ReflectFrom(&testPeer{
PublicKey: "pubClientKey5",
PresharedKey: "psKey5",
AllowedIPs: []string{"10.2.0.6/32,fd00:2::6/128"},
})
require.NoError(t, err)
buf = bytes.Buffer{}
_, err = cfg.WriteTo(&buf)
require.NoError(t, err)
assert.Equal(t, `[Interface]
Address = 10.2.0.1/24
ListenPort = 34777
PrivateKey = privServerKey
[Peer]
PublicKey = pubClientKey5
PresharedKey = psKey5
AllowedIPs = 10.2.0.6/32,fd00:2::6/128
`,
buf.String(),
)
})
}
// Inspired by https://github.com/go-ini/ini/issues/196
func TestMapToAndReflectFromStructWithShadows(t *testing.T) {
t.Run("map to struct and then reflect with shadows should generate original config content", func(t *testing.T) {
type include struct {
Paths []string `ini:"path,omitempty,allowshadow"`
}
cfg, err := LoadSources(LoadOptions{
AllowShadows: true,
}, []byte(`
[include]
path = /tmp/gpm-profiles/test5.profile
path = /tmp/gpm-profiles/test1.profile`))
require.NoError(t, err)
sec := cfg.Section("include")
inc := new(include)
err = sec.MapTo(inc)
require.NoError(t, err)
err = sec.ReflectFrom(inc)
require.NoError(t, err)
var buf bytes.Buffer
_, err = cfg.WriteTo(&buf)
require.NoError(t, err)
assert.Equal(t, `[include]
path = /tmp/gpm-profiles/test5.profile
path = /tmp/gpm-profiles/test1.profile
`,
buf.String(),
)
t.Run("reflect from struct with shadows", func(t *testing.T) {
cfg := Empty(LoadOptions{
AllowShadows: true,
})
type ShadowStruct struct {
StringArray []string `ini:"sa,allowshadow"`
EmptyStringArrat []string `ini:"empty,omitempty,allowshadow"`
Allowshadow []string `ini:"allowshadow,allowshadow"`
Dates []time.Time `ini:",allowshadow"`
Places []string `ini:",allowshadow"`
Years []int `ini:",allowshadow"`
Numbers []int64 `ini:",allowshadow"`
Ages []uint `ini:",allowshadow"`
Populations []uint64 `ini:",allowshadow"`
Coordinates []float64 `ini:",allowshadow"`
Flags []bool `ini:",allowshadow"`
None []int `ini:",allowshadow"`
}
shadow := &ShadowStruct{
StringArray: []string{"s1", "s2"},
Allowshadow: []string{"s3", "s4"},
Dates: []time.Time{time.Date(2020, 9, 12, 00, 00, 00, 651387237, time.UTC),
time.Date(2020, 9, 12, 00, 00, 00, 651387237, time.UTC)},
Places: []string{"HangZhou", "Boston"},
Years: []int{1993, 1994},
Numbers: []int64{10010, 10086},
Ages: []uint{18, 19},
Populations: []uint64{12345678, 98765432},
Coordinates: []float64{192.168, 10.11},
Flags: []bool{true, false},
None: []int{},
}
assert.NoError(t, ReflectFrom(cfg, shadow))
var buf bytes.Buffer
_, err := cfg.WriteTo(&buf)
require.NoError(t, err)
assert.Equal(t, `sa = s1
sa = s2
allowshadow = s3
allowshadow = s4
Dates = 2020-09-12T00:00:00Z
Places = HangZhou
Places = Boston
Years = 1993
Years = 1994
Numbers = 10010
Numbers = 10086
Ages = 18
Ages = 19
Populations = 12345678
Populations = 98765432
Coordinates = 192.168
Coordinates = 10.11
Flags = true
Flags = false
None =
`,
buf.String(),
)
})
})
}
type testMapper struct {
PackageName string
}
func Test_NameGetter(t *testing.T) {
t.Run("test name mappers", func(t *testing.T) {
assert.NoError(t, MapToWithMapper(&testMapper{}, TitleUnderscore, []byte("packag_name=ini")))
cfg, err := Load([]byte("PACKAGE_NAME=ini"))
require.NoError(t, err)
require.NotNil(t, cfg)
cfg.NameMapper = SnackCase
tg := new(testMapper)
assert.NoError(t, cfg.MapTo(tg))
assert.Equal(t, "ini", tg.PackageName)
})
}
type testDurationStruct struct {
Duration time.Duration `ini:"Duration"`
}
func Test_Duration(t *testing.T) {
t.Run("duration less than 16m50s", func(t *testing.T) {
ds := new(testDurationStruct)
assert.NoError(t, MapTo(ds, []byte("Duration=16m49s")))
dur, err := time.ParseDuration("16m49s")
require.NoError(t, err)
assert.Equal(t, dur.Seconds(), ds.Duration.Seconds())
})
}
type Employer struct {
Name string
Title string
}
type Employers []*Employer
func (es Employers) ReflectINIStruct(f *File) error {
for _, e := range es {
f.Section(e.Name).Key("Title").SetValue(e.Title)
}
return nil
}
// Inspired by https://github.com/go-ini/ini/issues/199
func Test_StructReflector(t *testing.T) {
t.Run("reflect with StructReflector interface", func(t *testing.T) {
p := &struct {
FirstName string
Employer Employers
}{
FirstName: "Andrew",
Employer: []*Employer{
{
Name: `Employer "VMware"`,
Title: "Staff II Engineer",
},
{
Name: `Employer "EMC"`,
Title: "Consultant Engineer",
},
},
}
f := Empty()
assert.NoError(t, f.ReflectFrom(p))
var buf bytes.Buffer
_, err := f.WriteTo(&buf)
require.NoError(t, err)
assert.Equal(t, `FirstName = Andrew
[Employer "VMware"]
Title = Staff II Engineer
[Employer "EMC"]
Title = Consultant Engineer
`,
buf.String(),
)
})
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。