From be544f963e4e39e884b36500a23d219eb6c61716 Mon Sep 17 00:00:00 2001 From: ysqi Date: Sat, 23 Jan 2016 11:02:40 +0800 Subject: [PATCH] Support Parse Bool with more diffrent values 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. --- config/config.go | 38 +++++++++++ config/fake.go | 2 +- config/ini.go | 2 +- config/ini_test.go | 104 ++++++++++++++++++------------ config/json.go | 8 +-- config/json_test.go | 153 +++++++++++++++++++++++++------------------- config/xml/xml.go | 6 +- config/yaml/yaml.go | 7 +- 8 files changed, 202 insertions(+), 118 deletions(-) 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