├── configor.go ├── README.md ├── utils.go └── configor_test.go /configor.go: -------------------------------------------------------------------------------- 1 | package configor 2 | 3 | import ( 4 | "os" 5 | "regexp" 6 | ) 7 | 8 | type Configor struct { 9 | *Config 10 | } 11 | 12 | type Config struct { 13 | Environment string 14 | ENVPrefix string 15 | } 16 | 17 | // New initialize a Configor 18 | func New(config *Config) *Configor { 19 | if config == nil { 20 | config = &Config{} 21 | } 22 | return &Configor{Config: config} 23 | } 24 | 25 | // GetEnvironment get environment 26 | func (configor *Configor) GetEnvironment() string { 27 | if configor.Environment == "" { 28 | if env := os.Getenv("CONFIGOR_ENV"); env != "" { 29 | return env 30 | } 31 | 32 | if isTest, _ := regexp.MatchString("/_test/", os.Args[0]); isTest { 33 | return "test" 34 | } 35 | 36 | return "development" 37 | } 38 | return configor.Environment 39 | } 40 | 41 | // Load will unmarshal configurations to struct from files that you provide 42 | func (configor *Configor) Load(config interface{}, files ...string) error { 43 | for _, file := range configor.getConfigurationFiles(files...) { 44 | if err := processFile(config, file); err != nil { 45 | return err 46 | } 47 | } 48 | 49 | if prefix := configor.getENVPrefix(config); prefix == "-" { 50 | return processTags(config) 51 | } else { 52 | return processTags(config, prefix) 53 | } 54 | } 55 | 56 | // ENV return environment 57 | func ENV() string { 58 | return New(nil).GetEnvironment() 59 | } 60 | 61 | // Load will unmarshal configurations to struct from files that you provide 62 | func Load(config interface{}, files ...string) error { 63 | return New(nil).Load(config, files...) 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Configor 2 | 3 | Golang Configuration tool that support YAML, JSON, TOML, Shell Environment 4 | 5 | ## Usage 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "github.com/jinzhu/configor" 13 | ) 14 | 15 | var Config = struct { 16 | APPName string `default:"app name"` 17 | 18 | DB struct { 19 | Name string 20 | User string `default:"root"` 21 | Password string `required:"true" env:"DBPassword"` 22 | Port uint `default:"3306"` 23 | } 24 | 25 | Contacts []struct { 26 | Name string 27 | Email string `required:"true"` 28 | } 29 | }{} 30 | 31 | func main() { 32 | configor.Load(&Config, "config.yml") 33 | fmt.Printf("config: %#v", Config) 34 | } 35 | ``` 36 | 37 | With configuration file *config.yml*: 38 | 39 | ```yaml 40 | appname: test 41 | 42 | db: 43 | name: test 44 | user: test 45 | password: test 46 | port: 1234 47 | 48 | contacts: 49 | - name: i test 50 | email: test@test.com 51 | ``` 52 | 53 | # Advanced Usage 54 | 55 | * Load mutiple configurations 56 | 57 | ```go 58 | // Earlier configurations have higher priority 59 | configor.Load(&Config, "application.yml", "database.json") 60 | ``` 61 | 62 | * Load configuration by environment 63 | 64 | Use `CONFIGOR_ENV` to set environment, if `CONFIGOR_ENV` not set, environment will be `development` by default, and it will be `test` when running tests with `go test` 65 | 66 | ```go 67 | // config.go 68 | configor.Load(&Config, "config.json") 69 | 70 | $ go run config.go 71 | // Will load `config.json`, `config.development.json` if it exists 72 | // `config.development.json` will overwrite `config.json`'s configuration 73 | // You could use this to share same configuration across different environments 74 | 75 | $ CONFIGOR_ENV=production go run config.go 76 | // Will load `config.json`, `config.production.json` if it exists 77 | // `config.production.json` will overwrite `config.json`'s configuration 78 | 79 | $ go test 80 | // Will load `config.json`, `config.test.json` if it exists 81 | // `config.test.json` will overwrite `config.json`'s configuration 82 | 83 | $ CONFIGOR_ENV=production go test 84 | // Will load `config.json`, `config.production.json` if it exists 85 | // `config.production.json` will overwrite `config.json`'s configuration 86 | ``` 87 | 88 | ```go 89 | // Set environment by config 90 | configor.New(&configor.Config{Environment: "production"}).Load(&Config, "config.json") 91 | ``` 92 | 93 | * Example Configuration 94 | 95 | ```go 96 | // config.go 97 | configor.Load(&Config, "config.yml") 98 | 99 | $ go run config.go 100 | // Will load `config.example.yml` automatically if `config.yml` not found and print warning message 101 | ``` 102 | 103 | * Load From Shell Environment 104 | 105 | ```go 106 | $ CONFIGOR_APPNAME="hello world" CONFIGOR_DB_NAME="hello world" go run config.go 107 | // Load configuration from shell environment, it's name is {{prefix}}_FieldName 108 | ``` 109 | 110 | ```go 111 | // You could overwrite the prefix with environment CONFIGOR_ENV_PREFIX, for example: 112 | $ CONFIGOR_ENV_PREFIX="WEB" WEB_APPNAME="hello world" WEB_DB_NAME="hello world" go run config.go 113 | 114 | // Set prefix by config 115 | configor.New(&configor.Config{ENVPrefix: "WEB"}).Load(&Config, "config.json") 116 | ``` 117 | 118 | * Anonymous Struct 119 | 120 | Add the `anonymous:"true"` tag to an anonymous, embedded struct to NOT include the struct name in the environment 121 | variable of any contained fields. For example: 122 | 123 | ```go 124 | type Details struct { 125 | Description string 126 | } 127 | 128 | type Config struct { 129 | Details `anonymous:"true"` 130 | } 131 | ``` 132 | 133 | With the `anonymous:"true"` tag specified, the environment variable for the `Description` field is `CONFIGOR_DESCRIPTION`. 134 | Without the `anonymous:"true"`tag specified, then environment variable would include the embedded struct name and be `CONFIGOR_DETAILS_DESCRIPTION`. 135 | 136 | * With flags 137 | 138 | ```go 139 | func main() { 140 | config := flag.String("file", "config.yml", "configuration file") 141 | flag.StringVar(&Config.APPName, "name", "", "app name") 142 | flag.StringVar(&Config.DB.Name, "db-name", "", "database name") 143 | flag.StringVar(&Config.DB.User, "db-user", "root", "database user") 144 | flag.Parse() 145 | 146 | os.Setenv("CONFIGOR_ENV_PREFIX", "-") 147 | configor.Load(&Config, *config) 148 | // configor.Load(&Config) // only load configurations from shell env & flag 149 | } 150 | ``` 151 | 152 | ## Supporting the project 153 | 154 | [![http://patreon.com/jinzhu](http://patreon_public_assets.s3.amazonaws.com/sized/becomeAPatronBanner.png)](http://patreon.com/jinzhu) 155 | 156 | 157 | ## Author 158 | 159 | **jinzhu** 160 | 161 | * 162 | * 163 | * 164 | 165 | ## License 166 | 167 | Released under the MIT License 168 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package configor 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "path" 10 | "reflect" 11 | "strings" 12 | 13 | "github.com/BurntSushi/toml" 14 | yaml "gopkg.in/yaml.v1" 15 | ) 16 | 17 | func (configor *Configor) getENVPrefix(config interface{}) string { 18 | if configor.Config.ENVPrefix == "" { 19 | if prefix := os.Getenv("CONFIGOR_ENV_PREFIX"); prefix != "" { 20 | return prefix 21 | } 22 | return "Configor" 23 | } 24 | return configor.Config.ENVPrefix 25 | } 26 | 27 | func getConfigurationFileWithENVPrefix(file, env string) (string, error) { 28 | var ( 29 | envFile string 30 | extname = path.Ext(file) 31 | ) 32 | 33 | if extname == "" { 34 | envFile = fmt.Sprintf("%v.%v", file, env) 35 | } else { 36 | envFile = fmt.Sprintf("%v.%v%v", strings.TrimSuffix(file, extname), env, extname) 37 | } 38 | 39 | if fileInfo, err := os.Stat(envFile); err == nil && fileInfo.Mode().IsRegular() { 40 | return envFile, nil 41 | } 42 | return "", fmt.Errorf("failed to find file %v", file) 43 | } 44 | 45 | func (configor *Configor) getConfigurationFiles(files ...string) []string { 46 | var results []string 47 | 48 | for i := len(files) - 1; i >= 0; i-- { 49 | foundFile := false 50 | file := files[i] 51 | 52 | // check configuration 53 | if fileInfo, err := os.Stat(file); err == nil && fileInfo.Mode().IsRegular() { 54 | foundFile = true 55 | results = append(results, file) 56 | } 57 | 58 | // check configuration with env 59 | if file, err := getConfigurationFileWithENVPrefix(file, configor.GetEnvironment()); err == nil { 60 | foundFile = true 61 | results = append(results, file) 62 | } 63 | 64 | // check example configuration 65 | if !foundFile { 66 | if example, err := getConfigurationFileWithENVPrefix(file, "example"); err == nil { 67 | fmt.Printf("Failed to find configuration %v, using example file %v\n", file, example) 68 | results = append(results, example) 69 | } else { 70 | fmt.Printf("Failed to find configuration %v\n", file) 71 | } 72 | } 73 | } 74 | return results 75 | } 76 | 77 | func processFile(config interface{}, file string) error { 78 | data, err := ioutil.ReadFile(file) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | switch { 84 | case strings.HasSuffix(file, ".yaml") || strings.HasSuffix(file, ".yml"): 85 | return yaml.Unmarshal(data, config) 86 | case strings.HasSuffix(file, ".toml"): 87 | return toml.Unmarshal(data, config) 88 | case strings.HasSuffix(file, ".json"): 89 | return json.Unmarshal(data, config) 90 | default: 91 | if toml.Unmarshal(data, config) != nil { 92 | if json.Unmarshal(data, config) != nil { 93 | if yaml.Unmarshal(data, config) != nil { 94 | return errors.New("failed to decode config") 95 | } 96 | } 97 | } 98 | return nil 99 | } 100 | } 101 | 102 | func getPrefixForStruct(prefixes []string, fieldStruct *reflect.StructField) []string { 103 | if fieldStruct.Anonymous && fieldStruct.Tag.Get("anonymous") == "true" { 104 | return prefixes 105 | } 106 | return append(prefixes, fieldStruct.Name) 107 | } 108 | 109 | func processTags(config interface{}, prefixes ...string) error { 110 | configValue := reflect.Indirect(reflect.ValueOf(config)) 111 | if configValue.Kind() != reflect.Struct { 112 | return errors.New("invalid config, should be struct") 113 | } 114 | 115 | configType := configValue.Type() 116 | for i := 0; i < configType.NumField(); i++ { 117 | var ( 118 | envNames []string 119 | fieldStruct = configType.Field(i) 120 | field = configValue.Field(i) 121 | envName = fieldStruct.Tag.Get("env") // read configuration from shell env 122 | ) 123 | 124 | if !field.CanAddr() || !field.CanInterface() { 125 | continue 126 | } 127 | 128 | if envName == "" { 129 | envNames = append(envNames, strings.Join(append(prefixes, fieldStruct.Name), "_")) // Configor_DB_Name 130 | envNames = append(envNames, strings.ToUpper(strings.Join(append(prefixes, fieldStruct.Name), "_"))) // CONFIGOR_DB_NAME 131 | } else { 132 | envNames = []string{envName} 133 | } 134 | 135 | // Load From Shell ENV 136 | for _, env := range envNames { 137 | if value := os.Getenv(env); value != "" { 138 | if err := yaml.Unmarshal([]byte(value), field.Addr().Interface()); err != nil { 139 | return err 140 | } 141 | break 142 | } 143 | } 144 | 145 | if isBlank := reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()); isBlank { 146 | // Set default configuration if blank 147 | if value := fieldStruct.Tag.Get("default"); value != "" { 148 | if err := yaml.Unmarshal([]byte(value), field.Addr().Interface()); err != nil { 149 | return err 150 | } 151 | } else if fieldStruct.Tag.Get("required") == "true" { 152 | // return error if it is required but blank 153 | return errors.New(fieldStruct.Name + " is required, but blank") 154 | } 155 | } 156 | 157 | for field.Kind() == reflect.Ptr { 158 | field = field.Elem() 159 | } 160 | 161 | if field.Kind() == reflect.Struct { 162 | if err := processTags(field.Addr().Interface(), getPrefixForStruct(prefixes, &fieldStruct)...); err != nil { 163 | return err 164 | } 165 | } 166 | 167 | if field.Kind() == reflect.Slice { 168 | for i := 0; i < field.Len(); i++ { 169 | if reflect.Indirect(field.Index(i)).Kind() == reflect.Struct { 170 | if err := processTags(field.Index(i).Addr().Interface(), append(getPrefixForStruct(prefixes, &fieldStruct), fmt.Sprint(i))...); err != nil { 171 | return err 172 | } 173 | } 174 | } 175 | } 176 | } 177 | return nil 178 | } 179 | -------------------------------------------------------------------------------- /configor_test.go: -------------------------------------------------------------------------------- 1 | package configor_test 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | "os" 8 | "reflect" 9 | "testing" 10 | 11 | "gopkg.in/yaml.v2" 12 | 13 | "github.com/BurntSushi/toml" 14 | "github.com/jinzhu/configor" 15 | ) 16 | 17 | type Anonymous struct { 18 | Description string 19 | } 20 | 21 | type Config struct { 22 | APPName string `default:"configor"` 23 | 24 | DB struct { 25 | Name string 26 | User string `default:"root"` 27 | Password string `required:"true" env:"DBPassword"` 28 | Port uint `default:"3306"` 29 | } 30 | 31 | Contacts []struct { 32 | Name string 33 | Email string `required:"true"` 34 | } 35 | 36 | Anonymous `anonymous:"true"` 37 | 38 | private string 39 | } 40 | 41 | func generateDefaultConfig() Config { 42 | config := Config{ 43 | APPName: "configor", 44 | DB: struct { 45 | Name string 46 | User string `default:"root"` 47 | Password string `required:"true" env:"DBPassword"` 48 | Port uint `default:"3306"` 49 | }{ 50 | Name: "configor", 51 | User: "configor", 52 | Password: "configor", 53 | Port: 3306, 54 | }, 55 | Contacts: []struct { 56 | Name string 57 | Email string `required:"true"` 58 | }{ 59 | { 60 | Name: "Jinzhu", 61 | Email: "wosmvp@gmail.com", 62 | }, 63 | }, 64 | Anonymous: Anonymous{ 65 | Description: "This is an anonymous embedded struct whose environment variables should NOT include 'ANONYMOUS'", 66 | }, 67 | } 68 | return config 69 | } 70 | 71 | func TestLoadNormalConfig(t *testing.T) { 72 | config := generateDefaultConfig() 73 | if bytes, err := json.Marshal(config); err == nil { 74 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 75 | defer file.Close() 76 | defer os.Remove(file.Name()) 77 | file.Write(bytes) 78 | 79 | var result Config 80 | configor.Load(&result, file.Name()) 81 | if !reflect.DeepEqual(result, config) { 82 | t.Errorf("result should equal to original configuration") 83 | } 84 | } 85 | } else { 86 | t.Errorf("failed to marshal config") 87 | } 88 | } 89 | 90 | func TestLoadConfigFromTomlWithExtension(t *testing.T) { 91 | var ( 92 | config = generateDefaultConfig() 93 | buffer bytes.Buffer 94 | ) 95 | 96 | if err := toml.NewEncoder(&buffer).Encode(config); err == nil { 97 | if file, err := ioutil.TempFile("/tmp", "configor.toml"); err == nil { 98 | defer file.Close() 99 | defer os.Remove(file.Name()) 100 | file.Write(buffer.Bytes()) 101 | 102 | var result Config 103 | configor.Load(&result, file.Name()) 104 | if !reflect.DeepEqual(result, config) { 105 | t.Errorf("result should equal to original configuration") 106 | } 107 | } 108 | } else { 109 | t.Errorf("failed to marshal config") 110 | } 111 | } 112 | 113 | func TestLoadConfigFromTomlWithoutExtension(t *testing.T) { 114 | var ( 115 | config = generateDefaultConfig() 116 | buffer bytes.Buffer 117 | ) 118 | 119 | if err := toml.NewEncoder(&buffer).Encode(config); err == nil { 120 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 121 | defer file.Close() 122 | defer os.Remove(file.Name()) 123 | file.Write(buffer.Bytes()) 124 | 125 | var result Config 126 | configor.Load(&result, file.Name()) 127 | if !reflect.DeepEqual(result, config) { 128 | t.Errorf("result should equal to original configuration") 129 | } 130 | } 131 | } else { 132 | t.Errorf("failed to marshal config") 133 | } 134 | } 135 | 136 | func TestDefaultValue(t *testing.T) { 137 | config := generateDefaultConfig() 138 | config.APPName = "" 139 | config.DB.Port = 0 140 | 141 | if bytes, err := json.Marshal(config); err == nil { 142 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 143 | defer file.Close() 144 | defer os.Remove(file.Name()) 145 | file.Write(bytes) 146 | 147 | var result Config 148 | configor.Load(&result, file.Name()) 149 | if !reflect.DeepEqual(result, generateDefaultConfig()) { 150 | t.Errorf("result should be set default value correctly") 151 | } 152 | } 153 | } else { 154 | t.Errorf("failed to marshal config") 155 | } 156 | } 157 | 158 | func TestMissingRequiredValue(t *testing.T) { 159 | config := generateDefaultConfig() 160 | config.DB.Password = "" 161 | 162 | if bytes, err := json.Marshal(config); err == nil { 163 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 164 | defer file.Close() 165 | defer os.Remove(file.Name()) 166 | file.Write(bytes) 167 | 168 | var result Config 169 | if err := configor.Load(&result, file.Name()); err == nil { 170 | t.Errorf("Should got error when load configuration missing db password") 171 | } 172 | } 173 | } else { 174 | t.Errorf("failed to marshal config") 175 | } 176 | } 177 | 178 | func TestLoadConfigurationByEnvironment(t *testing.T) { 179 | config := generateDefaultConfig() 180 | config2 := struct { 181 | APPName string 182 | }{ 183 | APPName: "config2", 184 | } 185 | 186 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 187 | defer file.Close() 188 | defer os.Remove(file.Name()) 189 | configBytes, _ := yaml.Marshal(config) 190 | config2Bytes, _ := yaml.Marshal(config2) 191 | ioutil.WriteFile(file.Name()+".yaml", configBytes, 0644) 192 | defer os.Remove(file.Name() + ".yaml") 193 | ioutil.WriteFile(file.Name()+".production.yaml", config2Bytes, 0644) 194 | defer os.Remove(file.Name() + ".production.yaml") 195 | 196 | var result Config 197 | os.Setenv("CONFIGOR_ENV", "production") 198 | defer os.Setenv("CONFIGOR_ENV", "") 199 | if err := configor.Load(&result, file.Name()+".yaml"); err != nil { 200 | t.Errorf("No error should happen when load configurations, but got %v", err) 201 | } 202 | 203 | var defaultConfig = generateDefaultConfig() 204 | defaultConfig.APPName = "config2" 205 | if !reflect.DeepEqual(result, defaultConfig) { 206 | t.Errorf("result should be load configurations by environment correctly") 207 | } 208 | } 209 | } 210 | 211 | func TestLoadConfigurationByEnvironmentSetByConfig(t *testing.T) { 212 | config := generateDefaultConfig() 213 | config2 := struct { 214 | APPName string 215 | }{ 216 | APPName: "production_config2", 217 | } 218 | 219 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 220 | defer file.Close() 221 | defer os.Remove(file.Name()) 222 | configBytes, _ := yaml.Marshal(config) 223 | config2Bytes, _ := yaml.Marshal(config2) 224 | ioutil.WriteFile(file.Name()+".yaml", configBytes, 0644) 225 | defer os.Remove(file.Name() + ".yaml") 226 | ioutil.WriteFile(file.Name()+".production.yaml", config2Bytes, 0644) 227 | defer os.Remove(file.Name() + ".production.yaml") 228 | 229 | var result Config 230 | var Configor = configor.New(&configor.Config{Environment: "production"}) 231 | if Configor.Load(&result, file.Name()+".yaml"); err != nil { 232 | t.Errorf("No error should happen when load configurations, but got %v", err) 233 | } 234 | 235 | var defaultConfig = generateDefaultConfig() 236 | defaultConfig.APPName = "production_config2" 237 | if !reflect.DeepEqual(result, defaultConfig) { 238 | t.Errorf("result should be load configurations by environment correctly") 239 | } 240 | 241 | if Configor.GetEnvironment() != "production" { 242 | t.Errorf("configor's environment should be production") 243 | } 244 | } 245 | } 246 | 247 | func TestOverwriteConfigurationWithEnvironmentWithDefaultPrefix(t *testing.T) { 248 | config := generateDefaultConfig() 249 | 250 | if bytes, err := json.Marshal(config); err == nil { 251 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 252 | defer file.Close() 253 | defer os.Remove(file.Name()) 254 | file.Write(bytes) 255 | var result Config 256 | os.Setenv("CONFIGOR_APPNAME", "config2") 257 | os.Setenv("CONFIGOR_DB_NAME", "db_name") 258 | defer os.Setenv("CONFIGOR_APPNAME", "") 259 | defer os.Setenv("CONFIGOR_DB_NAME", "") 260 | configor.Load(&result, file.Name()) 261 | 262 | var defaultConfig = generateDefaultConfig() 263 | defaultConfig.APPName = "config2" 264 | defaultConfig.DB.Name = "db_name" 265 | if !reflect.DeepEqual(result, defaultConfig) { 266 | t.Errorf("result should equal to original configuration") 267 | } 268 | } 269 | } 270 | } 271 | 272 | func TestOverwriteConfigurationWithEnvironment(t *testing.T) { 273 | config := generateDefaultConfig() 274 | 275 | if bytes, err := json.Marshal(config); err == nil { 276 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 277 | defer file.Close() 278 | defer os.Remove(file.Name()) 279 | file.Write(bytes) 280 | var result Config 281 | os.Setenv("CONFIGOR_ENV_PREFIX", "app") 282 | os.Setenv("APP_APPNAME", "config2") 283 | os.Setenv("APP_DB_NAME", "db_name") 284 | defer os.Setenv("CONFIGOR_ENV_PREFIX", "") 285 | defer os.Setenv("APP_APPNAME", "") 286 | defer os.Setenv("APP_DB_NAME", "") 287 | configor.Load(&result, file.Name()) 288 | 289 | var defaultConfig = generateDefaultConfig() 290 | defaultConfig.APPName = "config2" 291 | defaultConfig.DB.Name = "db_name" 292 | if !reflect.DeepEqual(result, defaultConfig) { 293 | t.Errorf("result should equal to original configuration") 294 | } 295 | } 296 | } 297 | } 298 | 299 | func TestOverwriteConfigurationWithEnvironmentThatSetByConfig(t *testing.T) { 300 | config := generateDefaultConfig() 301 | 302 | if bytes, err := json.Marshal(config); err == nil { 303 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 304 | defer file.Close() 305 | defer os.Remove(file.Name()) 306 | file.Write(bytes) 307 | os.Setenv("APP1_APPName", "config2") 308 | os.Setenv("APP1_DB_Name", "db_name") 309 | defer os.Setenv("APP1_APPName", "") 310 | defer os.Setenv("APP1_DB_Name", "") 311 | 312 | var result Config 313 | var Configor = configor.New(&configor.Config{ENVPrefix: "APP1"}) 314 | Configor.Load(&result, file.Name()) 315 | 316 | var defaultConfig = generateDefaultConfig() 317 | defaultConfig.APPName = "config2" 318 | defaultConfig.DB.Name = "db_name" 319 | if !reflect.DeepEqual(result, defaultConfig) { 320 | t.Errorf("result should equal to original configuration") 321 | } 322 | } 323 | } 324 | } 325 | 326 | func TestResetPrefixToBlank(t *testing.T) { 327 | config := generateDefaultConfig() 328 | 329 | if bytes, err := json.Marshal(config); err == nil { 330 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 331 | defer file.Close() 332 | defer os.Remove(file.Name()) 333 | file.Write(bytes) 334 | var result Config 335 | os.Setenv("CONFIGOR_ENV_PREFIX", "-") 336 | os.Setenv("APPNAME", "config2") 337 | os.Setenv("DB_NAME", "db_name") 338 | defer os.Setenv("CONFIGOR_ENV_PREFIX", "") 339 | defer os.Setenv("APPNAME", "") 340 | defer os.Setenv("DB_NAME", "") 341 | configor.Load(&result, file.Name()) 342 | 343 | var defaultConfig = generateDefaultConfig() 344 | defaultConfig.APPName = "config2" 345 | defaultConfig.DB.Name = "db_name" 346 | if !reflect.DeepEqual(result, defaultConfig) { 347 | t.Errorf("result should equal to original configuration") 348 | } 349 | } 350 | } 351 | } 352 | 353 | func TestResetPrefixToBlank2(t *testing.T) { 354 | config := generateDefaultConfig() 355 | 356 | if bytes, err := json.Marshal(config); err == nil { 357 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 358 | defer file.Close() 359 | defer os.Remove(file.Name()) 360 | file.Write(bytes) 361 | var result Config 362 | os.Setenv("CONFIGOR_ENV_PREFIX", "-") 363 | os.Setenv("APPName", "config2") 364 | os.Setenv("DB_Name", "db_name") 365 | defer os.Setenv("CONFIGOR_ENV_PREFIX", "") 366 | defer os.Setenv("APPName", "") 367 | defer os.Setenv("DB_Name", "") 368 | configor.Load(&result, file.Name()) 369 | 370 | var defaultConfig = generateDefaultConfig() 371 | defaultConfig.APPName = "config2" 372 | defaultConfig.DB.Name = "db_name" 373 | if !reflect.DeepEqual(result, defaultConfig) { 374 | t.Errorf("result should equal to original configuration") 375 | } 376 | } 377 | } 378 | } 379 | 380 | func TestReadFromEnvironmentWithSpecifiedEnvName(t *testing.T) { 381 | config := generateDefaultConfig() 382 | 383 | if bytes, err := json.Marshal(config); err == nil { 384 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 385 | defer file.Close() 386 | defer os.Remove(file.Name()) 387 | file.Write(bytes) 388 | var result Config 389 | os.Setenv("DBPassword", "db_password") 390 | defer os.Setenv("DBPassword", "") 391 | configor.Load(&result, file.Name()) 392 | 393 | var defaultConfig = generateDefaultConfig() 394 | defaultConfig.DB.Password = "db_password" 395 | if !reflect.DeepEqual(result, defaultConfig) { 396 | t.Errorf("result should equal to original configuration") 397 | } 398 | } 399 | } 400 | } 401 | 402 | func TestAnonymousStruct(t *testing.T) { 403 | config := generateDefaultConfig() 404 | 405 | if bytes, err := json.Marshal(config); err == nil { 406 | if file, err := ioutil.TempFile("/tmp", "configor"); err == nil { 407 | defer file.Close() 408 | defer os.Remove(file.Name()) 409 | file.Write(bytes) 410 | var result Config 411 | os.Setenv("CONFIGOR_DESCRIPTION", "environment description") 412 | defer os.Setenv("CONFIGOR_DESCRIPTION", "") 413 | configor.Load(&result, file.Name()) 414 | 415 | var defaultConfig = generateDefaultConfig() 416 | defaultConfig.Anonymous.Description = "environment description" 417 | if !reflect.DeepEqual(result, defaultConfig) { 418 | t.Errorf("result should equal to original configuration") 419 | } 420 | } 421 | } 422 | } 423 | 424 | func TestENV(t *testing.T) { 425 | if configor.ENV() != "test" { 426 | t.Errorf("Env should be test when running `go test`") 427 | } 428 | 429 | os.Setenv("CONFIGOR_ENV", "production") 430 | defer os.Setenv("CONFIGOR_ENV", "") 431 | if configor.ENV() != "production" { 432 | t.Errorf("Env should be production when set it with CONFIGOR_ENV") 433 | } 434 | } 435 | --------------------------------------------------------------------------------