Repository: spf13/viper (go)

Issue:
`svType != tvType` during config merge when keys can have different types
In [Lefhook git hooks manager](https://github.com/evilmartians/lefthook) we had ability to skip some git hooks in [user's local config](https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md#local-config). That was done via `skip` boolean setting in the config where usually it wasn't specified in main config defaulting to `false`, but in local config user could set it to `true`. However, reverse situations also exists in the wild.

Recently we decided to allow users not only skip hooks always (`true`) or never (`false`) but also by more complex conditions (e.g. during `rebase` and `merge`). This means, that this setting now can have different types of values in different configs: either boolean, string, or list of strings.

However, when we tried to merge configs with these “multitype” setting, values were ignored. I'm not sure whether it is a bug in Viper (I couldn't find any reasoning for the current implementation), but at least surprising behavior. If there is a way to properly handle this situation without changing Viper, please let us know!

**Expected behavior (what you expected to happen)**:
When I merge two configs with keys of different types, values are being overriden by values from merging config.

**Actual behavior (what actually happened)**:
New values are ignored with following messages printed to stderr:
```
ERROR 2021/05/22 12:16:28 svType != tvType; key=skip, st=string, tt=bool, sv=rebase, tv=true
ERROR 2021/05/22 12:16:28 svType != tvType; key=skip, st=[]interface {}, tt=bool, sv=[rebase merge], tv=true
```

**Repl.it link**:
https://replit.com/@Envek/Viper-example#main.go

**Code reproducing the issue**:
```go
viper := viper.New()
viper.AddConfigPath(".")

viper.SetConfigName("lefthook")
_ = viper.ReadInConfig()

viper.SetConfigName("lefthook-local")
_ = viper.MergeInConfig()
	
fmt.Printf("\nAll configuration: %+v\n\n", viper.AllSettings())
```

Configuration files:
<details>
<summary>lefthook.yml</summary>

```yml
post-checkout:
  piped: true
  scripts:
    01-bundle-checkinstall:
      skip: true
    02-db-migrate:
      skip: true
    03-crystalball-update:
      skip: true
```
</details>

<details>
<summary>lefthook-local.yml</summary>

```yml
post-checkout:
  scripts:
    01-bundle-checkinstall:
      skip: false
    02-db-migrate:
      skip: rebase
    03-crystalball-update:
      skip:
        - rebase
        - merge
```
</details>

**Environment**:
- Viper version: 1.7.1
- Config source: file
- File format: YAML

**Anything else we should know?**:
Pull request in Lefthook where this behavior was discovered (more context can be found here): https://github.com/evilmartians/lefthook/pull/173
Similar issue in Viper: https://github.com/spf13/viper/issues/1134
Commit that introduces code of interest: [`991d18a`](https://github.com/spf13/viper/commit/991d18afb2404beca5bc475995bf76f38729cc8f#diff-786d4c5d3482047f0ac7e62876791b9f4ba727a70acd750cf0a1bdd19c51c3f1R992-R997)

And thank you for Viper!

Pull request:
Allow merging configs with different types of leaf values
This fixes the problem that appears when your base config has values with different type than the override, which is valid use case.

Fixes #1142

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 53ba804..3feb2e1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -17,6 +17,7 @@ jobs:
       matrix:
         os: [ubuntu-latest, macos-latest, windows-latest]
         go: ['1.14', '1.15', '1.16', '1.17']
+        tags: ['', 'viper_yaml3', 'viper_toml2']
     env:
       GOFLAGS: -mod=readonly
 
@@ -30,7 +31,12 @@ jobs:
         uses: actions/checkout@v2
 
       - name: Test
-        run: go test -race -v ./...
+        run: go test -race -tags '${{ matrix.tags }}' -v ./...
+        if: runner.os != 'Windows'
+
+      - name: Test (without race detector)
+        run: go test -tags '${{ matrix.tags }}' -v ./...
+        if: runner.os == 'Windows'
 
   lint:
     name: Lint
diff --git a/experimental_logger.go b/experimental_logger.go
new file mode 100644
index 0000000..206dad6
--- /dev/null
+++ b/experimental_logger.go
@@ -0,0 +1,11 @@
+//go:build viper_logger
+// +build viper_logger
+
+package viper
+
+// WithLogger sets a custom logger.
+func WithLogger(l Logger) Option {
+	return optionFunc(func(v *Viper) {
+		v.logger = l
+	})
+}
diff --git a/go.mod b/go.mod
index 91f39a3..598283e 100644
--- a/go.mod
+++ b/go.mod
@@ -8,15 +8,17 @@ require (
 	github.com/magiconair/properties v1.8.5
 	github.com/mitchellh/mapstructure v1.4.3
 	github.com/pelletier/go-toml v1.9.4
+	github.com/pelletier/go-toml/v2 v2.0.0-beta.6
 	github.com/sagikazarmark/crypt v0.4.0
-	github.com/spf13/afero v1.6.0
+	github.com/spf13/afero v1.8.0
 	github.com/spf13/cast v1.4.1
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/pflag v1.0.5
-	github.com/stretchr/testify v1.7.0
+	github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942
 	github.com/subosito/gotenv v1.2.0
 	gopkg.in/ini.v1 v1.66.2
 	gopkg.in/yaml.v2 v2.4.0
+	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 )
 
 require (
@@ -54,7 +56,7 @@ require (
 	go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect
 	go.etcd.io/etcd/client/v2 v2.305.1 // indirect
 	go.opencensus.io v0.23.0 // indirect
-	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
+	golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
 	golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
 	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
 	golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
@@ -65,5 +67,4 @@ require (
 	google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
 	google.golang.org/grpc v1.43.0 // indirect
 	google.golang.org/protobuf v1.27.1 // indirect
-	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 )
diff --git a/go.sum b/go.sum
index ceb4d98..bc91077 100644
--- a/go.sum
+++ b/go.sum
@@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
 cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
 cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
 cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
 cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
 cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
@@ -15,6 +16,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
 cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
 cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
 cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
 cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
 cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
 cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
@@ -46,6 +48,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
 cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
 cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
@@ -193,6 +196,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
 github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
 github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
@@ -206,6 +210,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
 github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
 github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU=
 github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
+github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/hashicorp/consul/api v1.12.0 h1:k3y1FYv6nuKyNTqj6w9gXOx5r5CfLj/k/euUeBXj1OY=
 github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
@@ -313,10 +318,14 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
 github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pelletier/go-toml/v2 v2.0.0-beta.6 h1:JFNqj2afbbhCqTiyN16D7Tudc/aaDzE2FBDk+VlBQnE=
+github.com/pelletier/go-toml/v2 v2.0.0-beta.6/go.mod h1:ke6xncR3W76Ba8xnVxkrZG0js6Rd2BsQEAYrfgJ6eQA=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
+github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@@ -344,8 +353,9 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
-github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
 github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
+github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60=
+github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
 github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
 github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
@@ -360,8 +370,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942 h1:t0lM6y/M5IiUZyvbBTcngso8SZEZICH7is9B6g/obVU=
+github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
@@ -396,8 +407,10 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
+golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -467,6 +480,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
 golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
@@ -547,6 +561,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -554,6 +569,7 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -631,6 +647,7 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@@ -718,7 +735,9 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
diff --git a/internal/encoding/toml/codec.go b/internal/encoding/toml/codec.go
index ad0a18b..ff1112c 100644
--- a/internal/encoding/toml/codec.go
+++ b/internal/encoding/toml/codec.go
@@ -1,3 +1,6 @@
+//go:build !viper_toml2
+// +build !viper_toml2
+
 package toml
 
 import (
diff --git a/internal/encoding/toml/codec2.go b/internal/encoding/toml/codec2.go
new file mode 100644
index 0000000..566b706
--- /dev/null
+++ b/internal/encoding/toml/codec2.go
@@ -0,0 +1,19 @@
+//go:build viper_toml2
+// +build viper_toml2
+
+package toml
+
+import (
+	"github.com/pelletier/go-toml/v2"
+)
+
+// Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding.
+type Codec struct{}
+
+func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
+	return toml.Marshal(v)
+}
+
+func (Codec) Decode(b []byte, v map[string]interface{}) error {
+	return toml.Unmarshal(b, &v)
+}
diff --git a/internal/encoding/yaml/codec.go b/internal/encoding/yaml/codec.go
index 5fa4b39..24cc19d 100644
--- a/internal/encoding/yaml/codec.go
+++ b/internal/encoding/yaml/codec.go
@@ -1,6 +1,6 @@
 package yaml
 
-import "gopkg.in/yaml.v2"
+// import "gopkg.in/yaml.v2"
 
 // Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding.
 type Codec struct{}
diff --git a/internal/encoding/yaml/yaml2.go b/internal/encoding/yaml/yaml2.go
new file mode 100644
index 0000000..ca29b84
--- /dev/null
+++ b/internal/encoding/yaml/yaml2.go
@@ -0,0 +1,14 @@
+//go:build !viper_yaml3
+// +build !viper_yaml3
+
+package yaml
+
+import yamlv2 "gopkg.in/yaml.v2"
+
+var yaml = struct {
+	Marshal   func(in interface{}) (out []byte, err error)
+	Unmarshal func(in []byte, out interface{}) (err error)
+}{
+	Marshal:   yamlv2.Marshal,
+	Unmarshal: yamlv2.Unmarshal,
+}
diff --git a/internal/encoding/yaml/yaml3.go b/internal/encoding/yaml/yaml3.go
new file mode 100644
index 0000000..96b8957
--- /dev/null
+++ b/internal/encoding/yaml/yaml3.go
@@ -0,0 +1,14 @@
+//go:build viper_yaml3
+// +build viper_yaml3
+
+package yaml
+
+import yamlv3 "gopkg.in/yaml.v3"
+
+var yaml = struct {
+	Marshal   func(in interface{}) (out []byte, err error)
+	Unmarshal func(in []byte, out interface{}) (err error)
+}{
+	Marshal:   yamlv3.Marshal,
+	Unmarshal: yamlv3.Unmarshal,
+}
diff --git a/viper.go b/viper.go
index e5accf7..3481d1d 100644
--- a/viper.go
+++ b/viper.go
@@ -1780,17 +1780,6 @@ func mergeMaps(
 
 		svType := reflect.TypeOf(sv)
 		tvType := reflect.TypeOf(tv)
-		if tvType != nil && svType != tvType { // Allow for the target to be nil
-			v.logger.Error(
-				"svType != tvType",
-				"key", sk,
-				"st", svType,
-				"tt", tvType,
-				"sv", sv,
-				"tv", tv,
-			)
-			continue
-		}
 
 		v.logger.Trace(
 			"processing",
@@ -1804,13 +1793,27 @@ func mergeMaps(
 		switch ttv := tv.(type) {
 		case map[interface{}]interface{}:
 			v.logger.Trace("merging maps (must convert)")
-			tsv := sv.(map[interface{}]interface{})
+			tsv, ok := sv.(map[interface{}]interface{})
+			if !ok {
+				v.logger.Error(
+					"Could not cast sv to map[interface{}]interface{}; key=%s, st=%v, tt=%v, sv=%v, tv=%v",
+					sk, svType, tvType, sv, tv)
+				continue
+			}
+
 			ssv := castToMapStringInterface(tsv)
 			stv := castToMapStringInterface(ttv)
 			mergeMaps(ssv, stv, ttv)
 		case map[string]interface{}:
 			v.logger.Trace("merging maps")
-			mergeMaps(sv.(map[string]interface{}), ttv, nil)
+			tsv, ok := sv.(map[string]interface{})
+			if !ok {
+				v.logger.Error(
+					"Could not cast sv to map[string]interface{}; key=%s, st=%v, tt=%v, sv=%v, tv=%v",
+					sk, svType, tvType, sv, tv)
+				continue
+			}
+			mergeMaps(tsv, ttv, nil)
 		default:
 			v.logger.Trace("setting value")
 			tgt[tk] = sv


Test patch:
diff --git a/internal/encoding/toml/codec2_test.go b/internal/encoding/toml/codec2_test.go
new file mode 100644
index 0000000..271e321
--- /dev/null
+++ b/internal/encoding/toml/codec2_test.go
@@ -0,0 +1,109 @@
+//go:build viper_toml2
+// +build viper_toml2
+
+package toml
+
+import (
+	"reflect"
+	"testing"
+)
+
+// original form of the data
+const original = `# key-value pair
+key = "value"
+list = ["item1", "item2", "item3"]
+
+[map]
+key = "value"
+
+# nested
+# map
+[nested_map]
+[nested_map.map]
+key = "value"
+list = [
+  "item1",
+  "item2",
+  "item3",
+]
+`
+
+// encoded form of the data
+const encoded = `key = 'value'
+list = ['item1', 'item2', 'item3']
+[map]
+key = 'value'
+
+[nested_map]
+[nested_map.map]
+key = 'value'
+list = ['item1', 'item2', 'item3']
+
+
+`
+
+// Viper's internal representation
+var data = map[string]interface{}{
+	"key": "value",
+	"list": []interface{}{
+		"item1",
+		"item2",
+		"item3",
+	},
+	"map": map[string]interface{}{
+		"key": "value",
+	},
+	"nested_map": map[string]interface{}{
+		"map": map[string]interface{}{
+			"key": "value",
+			"list": []interface{}{
+				"item1",
+				"item2",
+				"item3",
+			},
+		},
+	},
+}
+
+func TestCodec_Encode(t *testing.T) {
+	codec := Codec{}
+
+	b, err := codec.Encode(data)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if encoded != string(b) {
+		t.Fatalf("decoded value does not match the expected one\nactual:   %#v\nexpected: %#v", string(b), encoded)
+	}
+}
+
+func TestCodec_Decode(t *testing.T) {
+	t.Run("OK", func(t *testing.T) {
+		codec := Codec{}
+
+		v := map[string]interface{}{}
+
+		err := codec.Decode([]byte(original), v)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if !reflect.DeepEqual(data, v) {
+			t.Fatalf("decoded value does not match the expected one\nactual:   %#v\nexpected: %#v", v, data)
+		}
+	})
+
+	t.Run("InvalidData", func(t *testing.T) {
+		codec := Codec{}
+
+		v := map[string]interface{}{}
+
+		err := codec.Decode([]byte(`invalid data`), v)
+		if err == nil {
+			t.Fatal("expected decoding to fail")
+		}
+
+		t.Logf("decoding failed as expected: %s", err)
+	})
+}
diff --git a/internal/encoding/toml/codec_test.go b/internal/encoding/toml/codec_test.go
index 33435e6..c7a2756 100644
--- a/internal/encoding/toml/codec_test.go
+++ b/internal/encoding/toml/codec_test.go
@@ -1,3 +1,6 @@
+//go:build !viper_toml2
+// +build !viper_toml2
+
 package toml
 
 import (
diff --git a/internal/encoding/yaml/codec_test.go b/internal/encoding/yaml/codec_test.go
index d76a6c6..d24a013 100644
--- a/internal/encoding/yaml/codec_test.go
+++ b/internal/encoding/yaml/codec_test.go
@@ -5,93 +5,6 @@ import (
 	"testing"
 )
 
-// original form of the data
-const original = `# key-value pair
-key: value
-list:
-- item1
-- item2
-- item3
-map:
-  key: value
-
-# nested
-# map
-nested_map:
-  map:
-    key: value
-    list:
-    - item1
-    - item2
-    - item3
-`
-
-// encoded form of the data
-const encoded = `key: value
-list:
-- item1
-- item2
-- item3
-map:
-  key: value
-nested_map:
-  map:
-    key: value
-    list:
-    - item1
-    - item2
-    - item3
-`
-
-// decoded form of the data
-//
-// in case of YAML it's slightly different from Viper's internal representation
-// (eg. map is decoded into a map with interface key)
-var decoded = map[string]interface{}{
-	"key": "value",
-	"list": []interface{}{
-		"item1",
-		"item2",
-		"item3",
-	},
-	"map": map[interface{}]interface{}{
-		"key": "value",
-	},
-	"nested_map": map[interface{}]interface{}{
-		"map": map[interface{}]interface{}{
-			"key": "value",
-			"list": []interface{}{
-				"item1",
-				"item2",
-				"item3",
-			},
-		},
-	},
-}
-
-// Viper's internal representation
-var data = map[string]interface{}{
-	"key": "value",
-	"list": []interface{}{
-		"item1",
-		"item2",
-		"item3",
-	},
-	"map": map[string]interface{}{
-		"key": "value",
-	},
-	"nested_map": map[string]interface{}{
-		"map": map[string]interface{}{
-			"key": "value",
-			"list": []interface{}{
-				"item1",
-				"item2",
-				"item3",
-			},
-		},
-	},
-}
-
 func TestCodec_Encode(t *testing.T) {
 	codec := Codec{}
 
diff --git a/internal/encoding/yaml/yaml2_test.go b/internal/encoding/yaml/yaml2_test.go
new file mode 100644
index 0000000..e39d429
--- /dev/null
+++ b/internal/encoding/yaml/yaml2_test.go
@@ -0,0 +1,91 @@
+//go:build !viper_yaml3
+// +build !viper_yaml3
+
+package yaml
+
+// original form of the data
+const original = `# key-value pair
+key: value
+list:
+- item1
+- item2
+- item3
+map:
+  key: value
+
+# nested
+# map
+nested_map:
+  map:
+    key: value
+    list:
+    - item1
+    - item2
+    - item3
+`
+
+// encoded form of the data
+const encoded = `key: value
+list:
+- item1
+- item2
+- item3
+map:
+  key: value
+nested_map:
+  map:
+    key: value
+    list:
+    - item1
+    - item2
+    - item3
+`
+
+// decoded form of the data
+//
+// in case of YAML it's slightly different from Viper's internal representation
+// (eg. map is decoded into a map with interface key)
+var decoded = map[string]interface{}{
+	"key": "value",
+	"list": []interface{}{
+		"item1",
+		"item2",
+		"item3",
+	},
+	"map": map[interface{}]interface{}{
+		"key": "value",
+	},
+	"nested_map": map[interface{}]interface{}{
+		"map": map[interface{}]interface{}{
+			"key": "value",
+			"list": []interface{}{
+				"item1",
+				"item2",
+				"item3",
+			},
+		},
+	},
+}
+
+// Viper's internal representation
+var data = map[string]interface{}{
+	"key": "value",
+	"list": []interface{}{
+		"item1",
+		"item2",
+		"item3",
+	},
+	"map": map[string]interface{}{
+		"key": "value",
+	},
+	"nested_map": map[string]interface{}{
+		"map": map[string]interface{}{
+			"key": "value",
+			"list": []interface{}{
+				"item1",
+				"item2",
+				"item3",
+			},
+		},
+	},
+}
diff --git a/internal/encoding/yaml/yaml3_test.go b/internal/encoding/yaml/yaml3_test.go
new file mode 100644
index 0000000..6beb263
--- /dev/null
+++ b/internal/encoding/yaml/yaml3_test.go
@@ -0,0 +1,91 @@
+//go:build viper_yaml3
+// +build viper_yaml3
+
+package yaml
+
+// original form of the data
+const original = `# key-value pair
+key: value
+list:
+    - item1
+    - item2
+    - item3
+map:
+    key: value
+
+# nested
+# map
+nested_map:
+    map:
+        key: value
+        list:
+            - item1
+            - item2
+            - item3
+`
+
+// encoded form of the data
+const encoded = `key: value
+list:
+    - item1
+    - item2
+    - item3
+map:
+    key: value
+nested_map:
+    map:
+        key: value
+        list:
+            - item1
+            - item2
+            - item3
+`
+
+// decoded form of the data
+//
+// in case of YAML it's slightly different from Viper's internal representation
+// (eg. map is decoded into a map with interface key)
+var decoded = map[string]interface{}{
+	"key": "value",
+	"list": []interface{}{
+		"item1",
+		"item2",
+		"item3",
+	},
+	"map": map[string]interface{}{
+		"key": "value",
+	},
+	"nested_map": map[string]interface{}{
+		"map": map[string]interface{}{
+			"key": "value",
+			"list": []interface{}{
+				"item1",
+				"item2",
+				"item3",
+			},
+		},
+	},
+}
+
+// Viper's internal representation
+var data = map[string]interface{}{
+	"key": "value",
+	"list": []interface{}{
+		"item1",
+		"item2",
+		"item3",
+	},
+	"map": map[string]interface{}{
+		"key": "value",
+	},
+	"nested_map": map[string]interface{}{
+		"map": map[string]interface{}{
+			"key": "value",
+			"list": []interface{}{
+				"item1",
+				"item2",
+				"item3",
+			},
+		},
+	},
+}
diff --git a/viper_test.go b/viper_test.go
index 8c864f1..c41a1e7 100644
--- a/viper_test.go
+++ b/viper_test.go
@@ -33,21 +33,21 @@ import (
 	"github.com/spf13/viper/internal/testutil"
 )
 
-var yamlExample = []byte(`Hacker: true
-name: steve
-hobbies:
-- skateboarding
-- snowboarding
-- go
-clothing:
-  jacket: leather
-  trousers: denim
-  pants:
-    size: large
-age: 35
-eyes : brown
-beard: true
-`)
+// var yamlExample = []byte(`Hacker: true
+// name: steve
+// hobbies:
+//     - skateboarding
+//     - snowboarding
+//     - go
+// clothing:
+//     jacket: leather
+//     trousers: denim
+//     pants:
+//         size: large
+// age: 35
+// eyes : brown
+// beard: true
+// `)
 
 var yamlExampleWithExtras = []byte(`Existing: true
 Bogus: true
@@ -1558,21 +1558,21 @@ p_ppu = 0.55
 p_batters.batter.type = Regular
 `)
 
-var yamlWriteExpected = []byte(`age: 35
-beard: true
-clothing:
-  jacket: leather
-  pants:
-    size: large
-  trousers: denim
-eyes: brown
-hacker: true
-hobbies:
-- skateboarding
-- snowboarding
-- go
-name: steve
-`)
+// var yamlWriteExpected = []byte(`age: 35
+// beard: true
+// clothing:
+//     jacket: leather
+//     pants:
+//         size: large
+//     trousers: denim
+// eyes: brown
+// hacker: true
+// hobbies:
+//     - skateboarding
+//     - snowboarding
+//     - go
+// name: steve
+// `)
 
 func TestWriteConfig(t *testing.T) {
 	fs := afero.NewMemMapFs()
@@ -1912,6 +1912,24 @@ hello:
 fu: bar
 `)
 
+var jsonMergeExampleTgt = []byte(`
+{
+	"hello": {
+		"foo": null,
+		"pop": 123456
+	}
+}
+`)
+
+var jsonMergeExampleSrc = []byte(`
+{
+	"hello": {
+		"foo": "foo str",
+		"pop": "pop str"
+	}
+}
+`)
+
 func TestMergeConfig(t *testing.T) {
 	v := New()
 	v.SetConfigType("yml")
@@ -1984,6 +2002,26 @@ func TestMergeConfig(t *testing.T) {
 	}
 }
 
+func TestMergeConfigOverrideType(t *testing.T) {
+	v := New()
+	v.SetConfigType("json")
+	if err := v.ReadConfig(bytes.NewBuffer(jsonMergeExampleTgt)); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := v.MergeConfig(bytes.NewBuffer(jsonMergeExampleSrc)); err != nil {
+		t.Fatal(err)
+	}
+
+	if pop := v.GetString("hello.pop"); pop != "pop str" {
+		t.Fatalf("pop != \"pop str\", = %s", pop)
+	}
+
+	if foo := v.GetString("hello.foo"); foo != "foo str" {
+		t.Fatalf("foo != \"foo str\", = %s", foo)
+	}
+}
+
 func TestMergeConfigNoMerge(t *testing.T) {
 	v := New()
 	v.SetConfigType("yml")
@@ -2410,25 +2448,25 @@ func TestUnmarshal_DotSeparatorBackwardCompatibility(t *testing.T) {
 	assert.Equal(t, "cobra_flag", config.Foo.Bar)
 }
 
-var yamlExampleWithDot = []byte(`Hacker: true
-name: steve
-hobbies:
-  - skateboarding
-  - snowboarding
-  - go
-clothing:
-  jacket: leather
-  trousers: denim
-  pants:
-    size: large
-age: 35
-eyes : brown
-beard: true
-emails:
-  steve@hacker.com:
-    created: 01/02/03
-    active: true
-`)
+// var yamlExampleWithDot = []byte(`Hacker: true
+// name: steve
+// hobbies:
+//     - skateboarding
+//     - snowboarding
+//     - go
+// clothing:
+//     jacket: leather
+//     trousers: denim
+//     pants:
+//         size: large
+// age: 35
+// eyes : brown
+// beard: true
+// emails:
+//     steve@hacker.com:
+//         created: 01/02/03
+//         active: true
+// `)
 
 func TestKeyDelimiter(t *testing.T) {
 	v := NewWithOptions(KeyDelimiter("::"))
diff --git a/viper_yaml2_test.go b/viper_yaml2_test.go
new file mode 100644
index 0000000..5a8a51e
--- /dev/null
+++ b/viper_yaml2_test.go
@@ -0,0 +1,56 @@
+//go:build !viper_yaml3
+// +build !viper_yaml3
+
+package viper
+
+var yamlExample = []byte(`Hacker: true
+name: steve
+hobbies:
+- skateboarding
+- snowboarding
+- go
+clothing:
+  jacket: leather
+  trousers: denim
+  pants:
+    size: large
+age: 35
+eyes : brown
+beard: true
+`)
+
+var yamlWriteExpected = []byte(`age: 35
+beard: true
+clothing:
+  jacket: leather
+  pants:
+    size: large
+  trousers: denim
+eyes: brown
+hacker: true
+hobbies:
+- skateboarding
+- snowboarding
+- go
+name: steve
+`)
+
+var yamlExampleWithDot = []byte(`Hacker: true
+name: steve
+hobbies:
+- skateboarding
+- snowboarding
+- go
+clothing:
+  jacket: leather
+  trousers: denim
+  pants:
+    size: large
+age: 35
+eyes : brown
+beard: true
+emails:
+  steve@hacker.com:
+    created: 01/02/03
+    active: true
+`)
diff --git a/viper_yaml3_test.go b/viper_yaml3_test.go
new file mode 100644
index 0000000..c397865
--- /dev/null
+++ b/viper_yaml3_test.go
@@ -0,0 +1,56 @@
+//go:build viper_yaml3
+// +build viper_yaml3
+
+package viper
+
+var yamlExample = []byte(`Hacker: true
+name: steve
+hobbies:
+    - skateboarding
+    - snowboarding
+    - go
+clothing:
+    jacket: leather
+    trousers: denim
+    pants:
+        size: large
+age: 35
+eyes : brown
+beard: true
+`)
+
+var yamlWriteExpected = []byte(`age: 35
+beard: true
+clothing:
+    jacket: leather
+    pants:
+        size: large
+    trousers: denim
+eyes: brown
+hacker: true
+hobbies:
+    - skateboarding
+    - snowboarding
+    - go
+name: steve
+`)
+
+var yamlExampleWithDot = []byte(`Hacker: true
+name: steve
+hobbies:
+    - skateboarding
+    - snowboarding
+    - go
+clothing:
+    jacket: leather
+    trousers: denim
+    pants:
+        size: large
+age: 35
+eyes : brown
+beard: true
+emails:
+    steve@hacker.com:
+        created: 01/02/03
+        active: true
+`)