Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using RegisterAlias together with ReadConfig does not work? #560

Open
brocaar opened this issue Aug 30, 2018 · 2 comments
Open

Using RegisterAlias together with ReadConfig does not work? #560

brocaar opened this issue Aug 30, 2018 · 2 comments

Comments

@brocaar
Copy link

brocaar commented Aug 30, 2018

Context

During an update of my application I made a change to my configuration format and was hoping by using RegisterAlias, to deal with this change in a backwards compatible way. I'm not sure if the failing testcase below is expected behavior or not.

From the README example:

viper.RegisterAlias("loud", "Verbose")

viper.Set("verbose", true) // same result as next line
viper.Set("loud", true)   // same result as prior line

viper.GetBool("loud") // true
viper.GetBool("verbose") // true

As the example sets the value using two keys, my assumption is that ReadConfig would do the same as it is just an other way to set config variables.

Testcase

In my case, I wanted to refactor loud to verbose. I expect that by using an alias, I would be able to handle this change. However, depending if I'm using RegisterAlias(A, B) or RegisterAlias(B, A), either the "old" or "new" configuration file isn't parsed correctly:

import (
	"bytes"
	"testing"

	"github.com/spf13/viper"
)

type UnmarshalWithAliasConfig struct {
	Verbose bool `mapstructure:"verbose"`
}

func TestReadConfigWithAlias(t *testing.T) {
	tests := []struct {
		ConfigFile    string
		ExpectedValue bool
	}{
		{ // 0
			ConfigFile: `
			loud=true
			`,
			ExpectedValue: true,
		},
		{ // 1
			ConfigFile: `
			verbose=true
			`,
			ExpectedValue: true,
		},
	}

	for i, test := range tests {
		v := viper.New()

		// test 0 fails and test 1 passes
		v.RegisterAlias("loud", "verbose")

		// test 0 passes and test 1 fails
		// v.RegisterAlias("verbose", "loud")

		v.SetConfigType("toml")
		if err := v.ReadConfig(bytes.NewBuffer([]byte(test.ConfigFile))); err != nil {
			t.Fatal(err)
		}

		// instead of ReadConfig using Set makes the tests pass, it works
		// with either key name:
		// v.Set("verbose", true)
		// v.Set("loud", true)

		if v := v.GetBool("verbose"); v != test.ExpectedValue {
			t.Errorf("[%d] expected from GetBool: %t, got: %t", i, test.ExpectedValue, v)
		}

		var c UnmarshalWithAliasConfig
		if err := v.Unmarshal(&c); err != nil {
			t.Fatal(err)
		}

		if c.Verbose != test.ExpectedValue {
			t.Errorf("[%d] expected in struct: %t, got: %t", i, test.ExpectedValue, c.Verbose)
		}
	}
}
@therealmitchconnors
Copy link
Contributor

I think RegisterAlias has to be called after ReadConfig, as it mutates the config in memory...

@DerGut
Copy link

DerGut commented Jun 9, 2022

I think RegisterAlias has to be called after ReadConfig, as it mutates the config in memory...

Thanks for this comment! It took me way too long until I figured this out. I'll create a PR to add this to the README

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants