@@ -948,6 +948,105 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) {
948
948
}, & C )
949
949
}
950
950
951
+ func TestUnmarshalWithAutomaticEnv (t * testing.T ) {
952
+ t .Setenv ("PORT" , "1313" )
953
+ t .Setenv ("NAME" , "Steve" )
954
+ t .Setenv ("DURATION" , "1s1ms" )
955
+ t .Setenv ("MODES" , "1,2,3" )
956
+ t .Setenv ("SECRET" , "42" )
957
+ t .Setenv ("FILESYSTEM_SIZE" , "4096" )
958
+
959
+ type AuthConfig struct {
960
+ Secret string `mapstructure:"secret"`
961
+ }
962
+
963
+ type StorageConfig struct {
964
+ Size int `mapstructure:"size"`
965
+ }
966
+
967
+ type Configuration struct {
968
+ Port int `mapstructure:"port"`
969
+ Name string `mapstructure:"name"`
970
+ Duration time.Duration `mapstructure:"duration"`
971
+
972
+ // Infer name from struct
973
+ Modes []int
974
+
975
+ // Squash nested struct (omit prefix)
976
+ Authentication AuthConfig `mapstructure:",squash"`
977
+
978
+ // Different key
979
+ Storage StorageConfig `mapstructure:"filesystem"`
980
+
981
+ // Omitted field
982
+ Flag bool `mapstructure:"flag"`
983
+ }
984
+
985
+ v := New ()
986
+ v .SetEnvKeyReplacer (strings .NewReplacer ("." , "_" ))
987
+ v .AutomaticEnv ()
988
+
989
+ t .Run ("OK" , func (t * testing.T ) {
990
+ var config Configuration
991
+ if err := v .Unmarshal (& config ); err != nil {
992
+ t .Fatalf ("unable to decode into struct, %v" , err )
993
+ }
994
+
995
+ assert .Equal (
996
+ t ,
997
+ Configuration {
998
+ Name : "Steve" ,
999
+ Port : 1313 ,
1000
+ Duration : time .Second + time .Millisecond ,
1001
+ Modes : []int {1 , 2 , 3 },
1002
+ Authentication : AuthConfig {
1003
+ Secret : "42" ,
1004
+ },
1005
+ Storage : StorageConfig {
1006
+ Size : 4096 ,
1007
+ },
1008
+ },
1009
+ config ,
1010
+ )
1011
+ })
1012
+
1013
+ t .Run ("Precedence" , func (t * testing.T ) {
1014
+ var config Configuration
1015
+
1016
+ v .Set ("port" , 1234 )
1017
+ if err := v .Unmarshal (& config ); err != nil {
1018
+ t .Fatalf ("unable to decode into struct, %v" , err )
1019
+ }
1020
+
1021
+ assert .Equal (
1022
+ t ,
1023
+ Configuration {
1024
+ Name : "Steve" ,
1025
+ Port : 1234 ,
1026
+ Duration : time .Second + time .Millisecond ,
1027
+ Modes : []int {1 , 2 , 3 },
1028
+ Authentication : AuthConfig {
1029
+ Secret : "42" ,
1030
+ },
1031
+ Storage : StorageConfig {
1032
+ Size : 4096 ,
1033
+ },
1034
+ },
1035
+ config ,
1036
+ )
1037
+ })
1038
+
1039
+ t .Run ("Unset" , func (t * testing.T ) {
1040
+ var config Configuration
1041
+
1042
+ err := v .Unmarshal (& config , func (config * mapstructure.DecoderConfig ) {
1043
+ config .ErrorUnset = true
1044
+ })
1045
+
1046
+ assert .Error (t , err , "expected viper.Unmarshal to return error due to unset field 'FLAG'" )
1047
+ })
1048
+ }
1049
+
951
1050
func TestBindPFlags (t * testing.T ) {
952
1051
v := New () // create independent Viper object
953
1052
flagSet := pflag .NewFlagSet ("test" , pflag .ContinueOnError )
0 commit comments