diff --git a/config/config.go b/config/config.go index da5d358b..e9df0f0e 100644 --- a/config/config.go +++ b/config/config.go @@ -106,3 +106,41 @@ func NewConfigData(adapterName string, data []byte) (Configer, error) { } return adapter.ParseData(data) } + +// ParseBool returns the boolean value represented by the string. +// +// It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On, +// 0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off. +// Any other value returns an error. +func ParseBool(val interface{}) (value bool, err error) { + + if val != nil { + switch v := val.(type) { + case bool: + return v, nil + case string: + switch v { + case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "Y", "y", "ON", "on", "On": + return true, nil + case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "N", "n", "OFF", "off", "Off": + return false, nil + } + case int8, int32, int64: + strV := fmt.Sprintf("%s", v) + if strV == "1" { + return true, nil + } else if strV == "0" { + return false, nil + } + case float64: + if v == 1 { + return true, nil + } else if v == 0 { + return false, nil + } + } + return false, fmt.Errorf("parsing %q: invalid syntax", val) + } else { + return false, fmt.Errorf("parsing : invalid syntax") + } +} diff --git a/config/fake.go b/config/fake.go index 50aa5d4a..6daaca2c 100644 --- a/config/fake.go +++ b/config/fake.go @@ -82,7 +82,7 @@ func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 { } func (c *fakeConfigContainer) Bool(key string) (bool, error) { - return strconv.ParseBool(c.getData(key)) + return ParseBool(c.getData(key)) } func (c *fakeConfigContainer) DefaultBool(key string, defaultval bool) bool { diff --git a/config/ini.go b/config/ini.go index 59e84e1e..6154b217 100644 --- a/config/ini.go +++ b/config/ini.go @@ -194,7 +194,7 @@ type IniConfigContainer struct { // Bool returns the boolean value for a given key. func (c *IniConfigContainer) Bool(key string) (bool, error) { - return strconv.ParseBool(c.getdata(key)) + return ParseBool(c.getdata(key)) } // DefaultBool returns the boolean value for a given key. diff --git a/config/ini_test.go b/config/ini_test.go index 7599ab8b..17643b6d 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -15,11 +15,15 @@ package config import ( + "fmt" "os" "testing" ) -var inicontext = ` +func TestIni(t *testing.T) { + + var ( + inicontext = ` ;comment one #comment two appname = beeapi @@ -29,6 +33,13 @@ PI = 3.1415976 runmode = "dev" autorender = false copyrequestbody = true +session= on +cookieon= off +newreg = OFF +needlogin = ON +enableSession = Y +enableCookie = N +flag = 1 [demo] key1="asta" key2 = "xie" @@ -36,7 +47,31 @@ CaseInsensitive = true peers = one;two;three ` -func TestIni(t *testing.T) { + keyValue = map[string]interface{}{ + "appname": "beeapi", + "httpport": 8080, + "mysqlport": int64(3600), + "pi": 3.1415976, + "runmode": "dev", + "autorender": false, + "copyrequestbody": true, + "session": true, + "cookieon": false, + "newreg": false, + "needlogin": true, + "enableSession": true, + "enableCookie": false, + "flag": true, + "demo::key1": "asta", + "demo::key2": "xie", + "demo::CaseInsensitive": true, + "demo::peers": []string{"one", "two", "three"}, + "null": "", + "demo2::key1": "", + "error": "", + } + ) + f, err := os.Create("testini.conf") if err != nil { t.Fatal(err) @@ -52,31 +87,31 @@ func TestIni(t *testing.T) { if err != nil { t.Fatal(err) } - if iniconf.String("appname") != "beeapi" { - t.Fatal("appname not equal to beeapi") - } - if port, err := iniconf.Int("httpport"); err != nil || port != 8080 { - t.Error(port) - t.Fatal(err) - } - if port, err := iniconf.Int64("mysqlport"); err != nil || port != 3600 { - t.Error(port) - t.Fatal(err) - } - if pi, err := iniconf.Float("PI"); err != nil || pi != 3.1415976 { - t.Error(pi) - t.Fatal(err) - } - if iniconf.String("runmode") != "dev" { - t.Fatal("runmode not equal to dev") - } - if v, err := iniconf.Bool("autorender"); err != nil || v != false { - t.Error(v) - t.Fatal(err) - } - if v, err := iniconf.Bool("copyrequestbody"); err != nil || v != true { - t.Error(v) - t.Fatal(err) + for k, v := range keyValue { + var err error + var value interface{} + switch v.(type) { + case int: + value, err = iniconf.Int(k) + case int64: + value, err = iniconf.Int64(k) + case float64: + value, err = iniconf.Float(k) + case bool: + value, err = iniconf.Bool(k) + case []string: + value = iniconf.Strings(k) + case string: + value = iniconf.String(k) + default: + value, err = iniconf.DIY(k) + } + if err != nil { + t.Fatalf("get key %q value fail,err %s", k, err) + } else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) { + t.Fatalf("get key %q value, want %v got %v .", k, v, value) + } + } if err = iniconf.Set("name", "astaxie"); err != nil { t.Fatal(err) @@ -84,20 +119,5 @@ func TestIni(t *testing.T) { if iniconf.String("name") != "astaxie" { t.Fatal("get name error") } - if iniconf.String("demo::key1") != "asta" { - t.Fatal("get demo.key1 error") - } - if iniconf.String("demo::key2") != "xie" { - t.Fatal("get demo.key2 error") - } - if v, err := iniconf.Bool("demo::caseinsensitive"); err != nil || v != true { - t.Fatal("get demo.caseinsensitive error") - } - - if data := iniconf.Strings("demo::peers"); len(data) != 3 { - t.Fatal("get strings error", data) - } else if data[0] != "one" { - t.Fatal("get first params error not equat to one") - } } diff --git a/config/json.go b/config/json.go index 65b4ac48..0bc1d456 100644 --- a/config/json.go +++ b/config/json.go @@ -17,6 +17,7 @@ package config import ( "encoding/json" "errors" + "fmt" "io/ioutil" "os" "strings" @@ -70,12 +71,9 @@ type JSONConfigContainer struct { func (c *JSONConfigContainer) Bool(key string) (bool, error) { val := c.getData(key) if val != nil { - if v, ok := val.(bool); ok { - return v, nil - } - return false, errors.New("not bool value") + return ParseBool(val) } - return false, errors.New("not exist key:" + key) + return false, fmt.Errorf("not exist key: %q", key) } // DefaultBool return the bool value if has no error diff --git a/config/json_test.go b/config/json_test.go index 5aedae36..9c06143e 100644 --- a/config/json_test.go +++ b/config/json_test.go @@ -15,34 +15,14 @@ package config import ( + "fmt" "os" "testing" ) -var jsoncontext = `{ -"appname": "beeapi", -"testnames": "foo;bar", -"httpport": 8080, -"mysqlport": 3600, -"PI": 3.1415976, -"runmode": "dev", -"autorender": false, -"copyrequestbody": true, -"database": { - "host": "host", - "port": "port", - "database": "database", - "username": "username", - "password": "password", - "conns":{ - "maxconnection":12, - "autoconnect":true, - "connectioninfo":"info" - } - } -}` +func TestJsonStartsWithArray(t *testing.T) { -var jsoncontextwitharray = `[ + const jsoncontextwitharray = `[ { "url": "user", "serviceAPI": "http://www.test.com/user" @@ -52,8 +32,6 @@ var jsoncontextwitharray = `[ "serviceAPI": "http://www.test.com/employee" } ]` - -func TestJsonStartsWithArray(t *testing.T) { f, err := os.Create("testjsonWithArray.conf") if err != nil { t.Fatal(err) @@ -90,6 +68,64 @@ func TestJsonStartsWithArray(t *testing.T) { } func TestJson(t *testing.T) { + + var ( + jsoncontext = `{ +"appname": "beeapi", +"testnames": "foo;bar", +"httpport": 8080, +"mysqlport": 3600, +"PI": 3.1415976, +"runmode": "dev", +"autorender": false, +"copyrequestbody": true, +"session": "on", +"cookieon": "off", +"newreg": "OFF", +"needlogin": "ON", +"enableSession": "Y", +"enableCookie": "N", +"flag": 1, +"database": { + "host": "host", + "port": "port", + "database": "database", + "username": "username", + "password": "password", + "conns":{ + "maxconnection":12, + "autoconnect":true, + "connectioninfo":"info" + } + } +}` + keyValue = map[string]interface{}{ + "appname": "beeapi", + "testnames": []string{"foo", "bar"}, + "httpport": 8080, + "mysqlport": int64(3600), + "PI": 3.1415976, + "runmode": "dev", + "autorender": false, + "copyrequestbody": true, + "session": true, + "cookieon": false, + "newreg": false, + "needlogin": true, + "enableSession": true, + "enableCookie": false, + "flag": true, + "database::host": "host", + "database::port": "port", + "database::database": "database", + "database::password": "password", + "database::conns::maxconnection": 12, + "database::conns::autoconnect": true, + "database::conns::connectioninfo": "info", + "unknown": "", + } + ) + f, err := os.Create("testjson.conf") if err != nil { t.Fatal(err) @@ -105,37 +141,32 @@ func TestJson(t *testing.T) { if err != nil { t.Fatal(err) } - if jsonconf.String("appname") != "beeapi" { - t.Fatal("appname not equal to beeapi") - } - if port, err := jsonconf.Int("httpport"); err != nil || port != 8080 { - t.Error(port) - t.Fatal(err) - } - if port, err := jsonconf.Int64("mysqlport"); err != nil || port != 3600 { - t.Error(port) - t.Fatal(err) - } - if pi, err := jsonconf.Float("PI"); err != nil || pi != 3.1415976 { - t.Error(pi) - t.Fatal(err) - } - if jsonconf.String("runmode") != "dev" { - t.Fatal("runmode not equal to dev") - } - if v := jsonconf.Strings("unknown"); len(v) > 0 { - t.Fatal("unknown strings, the length should be 0") - } - if v := jsonconf.Strings("testnames"); len(v) != 2 { - t.Fatal("testnames length should be 2") - } - if v, err := jsonconf.Bool("autorender"); err != nil || v != false { - t.Error(v) - t.Fatal(err) - } - if v, err := jsonconf.Bool("copyrequestbody"); err != nil || v != true { - t.Error(v) - t.Fatal(err) + + for k, v := range keyValue { + var err error + var value interface{} + switch v.(type) { + case int: + value, err = jsonconf.Int(k) + case int64: + value, err = jsonconf.Int64(k) + case float64: + value, err = jsonconf.Float(k) + case bool: + value, err = jsonconf.Bool(k) + case []string: + value = jsonconf.Strings(k) + case string: + value = jsonconf.String(k) + default: + value, err = jsonconf.DIY(k) + } + if err != nil { + t.Fatalf("get key %q value fatal,%V err %s", k, v, err) + } else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) { + t.Fatalf("get key %q value, want %v got %v .", k, v, value) + } + } if err = jsonconf.Set("name", "astaxie"); err != nil { t.Fatal(err) @@ -143,15 +174,7 @@ func TestJson(t *testing.T) { if jsonconf.String("name") != "astaxie" { t.Fatal("get name error") } - if jsonconf.String("database::host") != "host" { - t.Fatal("get database::host error") - } - if jsonconf.String("database::conns::connectioninfo") != "info" { - t.Fatal("get database::conns::connectioninfo error") - } - if maxconnection, err := jsonconf.Int("database::conns::maxconnection"); err != nil || maxconnection != 12 { - t.Fatal("get database::conns::maxconnection error") - } + if db, err := jsonconf.DIY("database"); err != nil { t.Fatal(err) } else if m, ok := db.(map[string]interface{}); !ok { diff --git a/config/xml/xml.go b/config/xml/xml.go index 4d48f7d2..662ef3d9 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -92,7 +92,11 @@ type ConfigContainer struct { // Bool returns the boolean value for a given key. func (c *ConfigContainer) Bool(key string) (bool, error) { - return strconv.ParseBool(c.data[key].(string)) + if v, ok := c.data[key]; ok { + return config.ParseBool(v) + } else { + return false, fmt.Errorf("not exist key: %q", key) + } } // DefaultBool return the bool value if has no error diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index f034d3ba..ccfd7b8b 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -121,10 +121,11 @@ type ConfigContainer struct { // Bool returns the boolean value for a given key. func (c *ConfigContainer) Bool(key string) (bool, error) { - if v, ok := c.data[key].(bool); ok { - return v, nil + if v, ok := c.data[key]; ok { + return config.ParseBool(v) + } else { + return false, fmt.Errorf("not exist key: %q", key) } - return false, errors.New("not bool value") } // DefaultBool return the bool value if has no error