Restructure the code a bit.
Add a more complete wrapper function called Configure and ConfigureWithDefaults. Add ability to write a configmap back to a new file. Changed my mind about multiple equals signs because some data like base64 uses equals signs. Added more tests. Bump to version 0.1.0 to signal closer to completeness/stability. Changed domain name from gitea.wisellama.rocks to git.wisellama.rocks.main v0.1.0
parent
5cc5aa419e
commit
4481060613
3
Makefile
3
Makefile
|
@ -1,8 +1,9 @@
|
||||||
all: linter test
|
all: linter test
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test ./
|
go test
|
||||||
|
|
||||||
|
lint: linter
|
||||||
linter:
|
linter:
|
||||||
golangci-lint run
|
golangci-lint run
|
||||||
|
|
||||||
|
|
60
Readme.md
60
Readme.md
|
@ -1,16 +1,18 @@
|
||||||
# gosimpleconf
|
# gosimpleconf
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
go get gitea.wisellama.rocks/Wisellama/gosimpleconf@v0.0.4
|
go get git.wisellama.rocks/Wisellama/gosimpleconf@v0.1.0
|
||||||
```
|
```
|
||||||
|
|
||||||
This is a small library for parsing super simple configuration files.
|
This is a small library for parsing super simple configuration files
|
||||||
|
similar to Unix conf files.
|
||||||
|
|
||||||
It expects a file with the following format:
|
It expects a file with the following format:
|
||||||
* Lines with key-values pairs separated by `=` (e.g. `foo = bar`)
|
* Lines with key-values pairs separated by `=` (e.g. `foo = bar`)
|
||||||
* Lines that start with `#` are ignored (used for comments)
|
* Lines that start with `#` are ignored (used for comments)
|
||||||
* Empty and whitespace-only lines are ignore
|
* Empty and whitespace-only lines are ignored
|
||||||
* Lines with data that don't have an `=` will cause an error.
|
* Lines with some data but no `=` will cause an error.
|
||||||
|
* Lines with multiple `=` are split on the literal first `=` seen, any remaining are part of the value.
|
||||||
|
|
||||||
The key-values pairs are simply parsed as strings and plopped into a
|
The key-values pairs are simply parsed as strings and plopped into a
|
||||||
map for you to do whatever your program wants with them. If you need a
|
map for you to do whatever your program wants with them. If you need a
|
||||||
|
@ -25,15 +27,21 @@ url = www.wisellama.rocks
|
||||||
number_of_widgets = 1337
|
number_of_widgets = 1337
|
||||||
pi = 3.141592653589793238462643383
|
pi = 3.141592653589793238462643383
|
||||||
environment = production
|
environment = production
|
||||||
|
|
||||||
# Quotes are optional
|
# Quotes are optional
|
||||||
name = Dude guy
|
name = Dude guy
|
||||||
description = "Just some dude it was"
|
description = "Just some dude it was"
|
||||||
|
|
||||||
|
# Additional equals are just part of the value
|
||||||
|
base64_tacos = dGFjb3M=
|
||||||
|
a=b=c
|
||||||
|
# key: 'a', value: 'b=c'
|
||||||
```
|
```
|
||||||
|
|
||||||
Then to load that config file into a map:
|
Then to load that config file into a map:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
configMap, err := gosimpleconf.Load("file.conf")
|
configMap, err := gosimpleconf.Configure("file.conf")
|
||||||
```
|
```
|
||||||
|
|
||||||
Then everything is a string. You can parse it as needed.
|
Then everything is a string. You can parse it as needed.
|
||||||
|
@ -42,19 +50,43 @@ var piStr string = configMap["pi"]
|
||||||
pi, err := strconv.ParseFloat(value, 64)
|
pi, err := strconv.ParseFloat(value, 64)
|
||||||
```
|
```
|
||||||
|
|
||||||
To override values with cli flags, after parsing the conf file you can
|
### Command-Line Flag Overrides
|
||||||
use these functions to also parse the flags:
|
|
||||||
```go
|
|
||||||
flagMap := SetupFlagOverrides(configMap)
|
|
||||||
configMap = ParseFlags(configMap, flagmap)
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you could, for example, override the url value without modifying
|
By default, the `Configure()` function will figure out which keys
|
||||||
the config file:
|
exist in the config map and set those as cli flags that you can
|
||||||
```go
|
override. For example, with the config file above, you could override
|
||||||
|
the `url` key with a cli flag:
|
||||||
|
```sh
|
||||||
./program --url=newthing.wisellama.rocks
|
./program --url=newthing.wisellama.rocks
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you don't want to support cli flag overrides, you can directly call
|
||||||
|
`ReadFile("file.conf")` instead.
|
||||||
|
|
||||||
|
If you want to support other cli flags that don't map to a config
|
||||||
|
setting, they must be set up before calling `Configure()`. This is
|
||||||
|
because the `ParseFlags()` function calls `flag.Parse()` to get all
|
||||||
|
the values for the config map overrides. You could also work around
|
||||||
|
this by calling `ReadFile` and `ParseFlags` yourself and add your
|
||||||
|
other logic in between the two calls.
|
||||||
|
|
||||||
|
### Default Config
|
||||||
|
|
||||||
|
You can specify a default configuration to return if the given config
|
||||||
|
file doesn't exist. Here's an example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
defaultConfig := gosimpleconf.ConfigMap{
|
||||||
|
"game.title": "Some Game",
|
||||||
|
"log.writeToFile": "false",
|
||||||
|
}
|
||||||
|
configMap, err := gosimpleconf.ConfigureWithDefaults("file_that_doesnt_exist.conf", defaultConfig)
|
||||||
|
```
|
||||||
|
|
||||||
|
Then if the config file can't be found, the default config map values
|
||||||
|
will be used instead. You can still override the default values with
|
||||||
|
cli flags.
|
||||||
|
|
||||||
## Why?
|
## Why?
|
||||||
|
|
||||||
I've always seen configuration files similar to this show up in
|
I've always seen configuration files similar to this show up in
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package gosimpleconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigMap map[string]string
|
||||||
|
|
||||||
|
func Load(filename string) (ConfigMap, error) {
|
||||||
|
return ReadFile(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadFile(filename string) (ConfigMap, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
parsedMap, err := parseFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteFile(filename string, configMap ConfigMap) error {
|
||||||
|
file, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
for k, v := range configMap {
|
||||||
|
fmt.Fprintf(file, "%s = %s\n", k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFile(config io.Reader) (ConfigMap, error) {
|
||||||
|
var err error
|
||||||
|
parsedMap := make(ConfigMap)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(config)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
trimmed := strings.TrimSpace(line)
|
||||||
|
if len(trimmed) == 0 {
|
||||||
|
// ignore empty lines
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if trimmed[0] == '#' {
|
||||||
|
// ignore comments
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
split := strings.Split(trimmed, "=")
|
||||||
|
if len(split) < 2 {
|
||||||
|
return nil, fmt.Errorf("failed to parse config line: %v", trimmed)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := trimToken(split[0])
|
||||||
|
|
||||||
|
value := strings.Join(split[1:], "=") // Re-add any ='s that were part of the value
|
||||||
|
value = trimToken(value)
|
||||||
|
|
||||||
|
parsedMap[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = scanner.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func trimToken(value string) string {
|
||||||
|
// Trim off whitespace
|
||||||
|
v := strings.TrimSpace(value)
|
||||||
|
|
||||||
|
// Trim off any surrounding quotes, everything is a string anyway
|
||||||
|
v = strings.TrimPrefix(v, "\"")
|
||||||
|
v = strings.TrimSuffix(v, "\"")
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package gosimpleconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseWithValidConfig(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
configFileStr := `
|
||||||
|
# Some config file
|
||||||
|
|
||||||
|
foo=bar
|
||||||
|
asdf = 1234
|
||||||
|
|
||||||
|
# Things
|
||||||
|
wat.wat= thing
|
||||||
|
foo.wat =stuff
|
||||||
|
|
||||||
|
immaempty=
|
||||||
|
|
||||||
|
technically valid = haha hmm...
|
||||||
|
|
||||||
|
#Done
|
||||||
|
`
|
||||||
|
configFile := strings.NewReader(configFileStr)
|
||||||
|
|
||||||
|
expectedMap := make(ConfigMap)
|
||||||
|
expectedMap["foo"] = "bar"
|
||||||
|
expectedMap["asdf"] = "1234"
|
||||||
|
expectedMap["wat.wat"] = "thing"
|
||||||
|
expectedMap["foo.wat"] = "stuff"
|
||||||
|
expectedMap["immaempty"] = ""
|
||||||
|
expectedMap["technically valid"] = "haha hmm..."
|
||||||
|
|
||||||
|
parsedMap, err := parseFile(configFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed while parsing the file")
|
||||||
|
}
|
||||||
|
|
||||||
|
validateMap(t, parsedMap, expectedMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseWithNoEquals(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
configFileStr := `
|
||||||
|
Something here with no equals to split on
|
||||||
|
`
|
||||||
|
configFile := strings.NewReader(configFileStr)
|
||||||
|
|
||||||
|
_, err = parseFile(configFile)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("parse did not thrown an error when it was supposed to")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseWithExtraQuotes(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
configFileStr := `
|
||||||
|
some.name = "This is in quotes"
|
||||||
|
extra.quotes = ""This will keep the quotes""
|
||||||
|
internal.quotes = "Some "thing" is here"
|
||||||
|
"This should work too" = shrug I guess
|
||||||
|
`
|
||||||
|
|
||||||
|
configFile := strings.NewReader(configFileStr)
|
||||||
|
|
||||||
|
expectedMap := make(ConfigMap)
|
||||||
|
expectedMap["some.name"] = "This is in quotes"
|
||||||
|
expectedMap["extra.quotes"] = "\"This will keep the quotes\""
|
||||||
|
expectedMap["internal.quotes"] = "Some \"thing\" is here"
|
||||||
|
expectedMap["This should work too"] = "shrug I guess"
|
||||||
|
|
||||||
|
configMap, err := parseFile(configFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed while parsing the file")
|
||||||
|
}
|
||||||
|
|
||||||
|
validateMap(t, configMap, expectedMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseExtraEquals(t *testing.T) {
|
||||||
|
configFileStr := `
|
||||||
|
foo=bar=true
|
||||||
|
base64_tacos = dGFjb3M=
|
||||||
|
"equals=splits" the key/value, quotes and other =equals= don't matter
|
||||||
|
yup=soup
|
||||||
|
`
|
||||||
|
|
||||||
|
configFile := strings.NewReader(configFileStr)
|
||||||
|
|
||||||
|
expectedMap := make(ConfigMap)
|
||||||
|
expectedMap["foo"] = "bar=true"
|
||||||
|
expectedMap["base64_tacos"] = "dGFjb3M="
|
||||||
|
expectedMap["equals"] = "splits\" the key/value, quotes and other =equals= don't matter"
|
||||||
|
expectedMap["yup"] = "soup"
|
||||||
|
|
||||||
|
configMap, err := parseFile(configFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed while parsing the file")
|
||||||
|
}
|
||||||
|
|
||||||
|
validateMap(t, configMap, expectedMap)
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package gosimpleconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Bool(value string) bool {
|
||||||
|
v, err := strconv.ParseBool(value)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error parsing bool %v - %v\n", v, err)
|
||||||
|
v = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func Int64(value string) int64 {
|
||||||
|
v, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error parsing int %v - %v\n", v, err)
|
||||||
|
v = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func Float64(value string) float64 {
|
||||||
|
v, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error parsing float %v - %v\n", v, err)
|
||||||
|
v = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package gosimpleconf
|
||||||
|
|
||||||
|
import "flag"
|
||||||
|
|
||||||
|
type FlagMap map[string]*string
|
||||||
|
|
||||||
|
func SetupFlagOverrides(configMap ConfigMap) FlagMap {
|
||||||
|
flagMap := make(FlagMap)
|
||||||
|
for k, v := range configMap {
|
||||||
|
f := flag.String(k, v, "")
|
||||||
|
flagMap[k] = f
|
||||||
|
}
|
||||||
|
|
||||||
|
return flagMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseFlags(configMap ConfigMap, flagMap FlagMap) ConfigMap {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
for k, v := range flagMap {
|
||||||
|
if v != nil && len(*v) > 0 {
|
||||||
|
configMap[k] = trimToken(*v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return configMap
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package gosimpleconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFlagOverrides(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
configFileStr := `
|
||||||
|
foo=bar
|
||||||
|
asdf = 1234
|
||||||
|
foo.wat =stuff
|
||||||
|
immaempty=
|
||||||
|
`
|
||||||
|
configFile := strings.NewReader(configFileStr)
|
||||||
|
|
||||||
|
expectedMap := make(ConfigMap)
|
||||||
|
expectedMap["foo"] = "bar"
|
||||||
|
expectedMap["asdf"] = "1234"
|
||||||
|
// expect to override the 'foo.wat' value with a cli flag
|
||||||
|
expectedMap["foo.wat"] = "iwasoverridden"
|
||||||
|
expectedMap["immaempty"] = ""
|
||||||
|
|
||||||
|
configMap, err := parseFile(configFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed while parsing the file")
|
||||||
|
}
|
||||||
|
|
||||||
|
flagMap := SetupFlagOverrides(configMap)
|
||||||
|
|
||||||
|
err = flag.Set("foo.wat", "iwasoverridden")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to set cli flag override")
|
||||||
|
}
|
||||||
|
|
||||||
|
configMap = ParseFlags(configMap, flagMap)
|
||||||
|
|
||||||
|
validateMap(t, configMap, expectedMap)
|
||||||
|
}
|
2
go.mod
2
go.mod
|
@ -1,3 +1,3 @@
|
||||||
module gitea.wisellama.rocks/Wisellama/gosimpleconf
|
module git.wisellama.rocks/Wisellama/gosimpleconf
|
||||||
|
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
109
gosimpleconf.go
109
gosimpleconf.go
|
@ -1,112 +1,31 @@
|
||||||
package gosimpleconf
|
package gosimpleconf
|
||||||
|
|
||||||
import (
|
import "os"
|
||||||
"bufio"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ConfigMap map[string]string
|
func Configure(filename string) (ConfigMap, error) {
|
||||||
type FlagMap map[string]*string
|
|
||||||
|
|
||||||
func Load(filename string) (ConfigMap, error) {
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
file, err := os.Open(filename)
|
configMap, err := ReadFile(filename)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
parsedMap, err := parseFile(file)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedMap, nil
|
flagMap := SetupFlagOverrides(configMap)
|
||||||
|
configMap = ParseFlags(configMap, flagMap)
|
||||||
|
|
||||||
|
return configMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupFlagOverrides(configMap ConfigMap) FlagMap {
|
func ConfigureWithDefaults(filename string, defaultConf ConfigMap) (ConfigMap, error) {
|
||||||
flagMap := make(FlagMap)
|
|
||||||
for k, v := range configMap {
|
|
||||||
f := flag.String(k, v, "")
|
|
||||||
flagMap[k] = f
|
|
||||||
}
|
|
||||||
|
|
||||||
return flagMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseFlags(configMap ConfigMap, flagMap FlagMap) ConfigMap {
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
for k, v := range flagMap {
|
|
||||||
if v != nil && len(*v) > 0 {
|
|
||||||
configMap[k] = trimToken(*v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return configMap
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func Bool(value string) bool {
|
|
||||||
v, err := strconv.ParseBool(value)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error parsing bool %v - %v\n", v, err)
|
|
||||||
v = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseFile(config io.Reader) (ConfigMap, error) {
|
|
||||||
var err error
|
var err error
|
||||||
parsedMap := make(ConfigMap)
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(config)
|
_, err = os.Stat(filename)
|
||||||
for scanner.Scan() {
|
if os.IsNotExist(err) {
|
||||||
line := scanner.Text()
|
// Config file does not exist, return a default configMap
|
||||||
trimmed := strings.TrimSpace(line)
|
return defaultConf, nil
|
||||||
if len(trimmed) == 0 {
|
} else if err != nil {
|
||||||
// ignore empty lines
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if trimmed[0] == '#' {
|
|
||||||
// ignore comments
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
split := strings.Split(trimmed, "=")
|
|
||||||
if len(split) != 2 {
|
|
||||||
return nil, fmt.Errorf("failed to parse config line: %v", trimmed)
|
|
||||||
}
|
|
||||||
|
|
||||||
key := trimToken(split[0])
|
|
||||||
value := trimToken(split[1])
|
|
||||||
|
|
||||||
parsedMap[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = scanner.Err(); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedMap, nil
|
return Configure(filename)
|
||||||
}
|
|
||||||
|
|
||||||
func trimToken(value string) string {
|
|
||||||
// Trim off whitespace
|
|
||||||
v := strings.TrimSpace(value)
|
|
||||||
|
|
||||||
// Trim off any surrounding quotes, everything is a string anyway
|
|
||||||
v = strings.TrimPrefix(v, "\"")
|
|
||||||
v = strings.TrimSuffix(v, "\"")
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,150 +1,40 @@
|
||||||
package gosimpleconf
|
package gosimpleconf
|
||||||
|
|
||||||
import (
|
import "testing"
|
||||||
"flag"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParseWithValidConfig(t *testing.T) {
|
func TestConfigureWithDefaults(t *testing.T) {
|
||||||
var err error
|
defaultMap := ConfigMap{
|
||||||
configFileStr := `
|
"some": "thing",
|
||||||
# Some config file
|
"cool": "1337",
|
||||||
|
}
|
||||||
|
|
||||||
foo=bar
|
filename := "idontexist_123456789"
|
||||||
asdf = 1234
|
|
||||||
|
|
||||||
# Things
|
conf, err := ConfigureWithDefaults(filename, defaultMap)
|
||||||
wat.wat= thing
|
|
||||||
foo.wat =stuff
|
|
||||||
|
|
||||||
immaempty=
|
|
||||||
|
|
||||||
technically valid = haha hmm...
|
|
||||||
|
|
||||||
#Done
|
|
||||||
`
|
|
||||||
configFile := strings.NewReader(configFileStr)
|
|
||||||
|
|
||||||
expectedMap := make(ConfigMap)
|
|
||||||
expectedMap["foo"] = "bar"
|
|
||||||
expectedMap["asdf"] = "1234"
|
|
||||||
expectedMap["wat.wat"] = "thing"
|
|
||||||
expectedMap["foo.wat"] = "stuff"
|
|
||||||
expectedMap["immaempty"] = ""
|
|
||||||
expectedMap["technically valid"] = "haha hmm..."
|
|
||||||
|
|
||||||
parsedMap, err := parseFile(configFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed while parsing the file")
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
validateMap(t, parsedMap, expectedMap)
|
validateMap(t, conf, defaultMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseWithExtraEquals(t *testing.T) {
|
func TestConfigure(t *testing.T) {
|
||||||
var err error
|
filename := "test.conf"
|
||||||
configFileStr := `
|
expectedMap := ConfigMap{
|
||||||
foo=bar=true
|
"url": "www.wisellama.rocks",
|
||||||
`
|
"number_of_widgets": "1337",
|
||||||
configFile := strings.NewReader(configFileStr)
|
"pi": "3.141592653589793238462643383",
|
||||||
|
"environment": "production",
|
||||||
_, err = parseFile(configFile)
|
"name": "Dude guy",
|
||||||
if err == nil {
|
"description": "Just some dude it was",
|
||||||
t.Errorf("parse did not thrown an error when it was supposed to")
|
"base64_tacos": "dGFjb3M=",
|
||||||
|
"a": "b=c",
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseWithNoEquals(t *testing.T) {
|
conf, err := Configure(filename)
|
||||||
var err error
|
|
||||||
configFileStr := `
|
|
||||||
Something here with no equals to split on
|
|
||||||
`
|
|
||||||
configFile := strings.NewReader(configFileStr)
|
|
||||||
|
|
||||||
_, err = parseFile(configFile)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("parse did not thrown an error when it was supposed to")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFlagOverrides(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
configFileStr := `
|
|
||||||
foo=bar
|
|
||||||
asdf = 1234
|
|
||||||
foo.wat =stuff
|
|
||||||
immaempty=
|
|
||||||
`
|
|
||||||
configFile := strings.NewReader(configFileStr)
|
|
||||||
|
|
||||||
expectedMap := make(ConfigMap)
|
|
||||||
expectedMap["foo"] = "bar"
|
|
||||||
expectedMap["asdf"] = "1234"
|
|
||||||
// expect to override the 'foo.wat' value with a cli flag
|
|
||||||
expectedMap["foo.wat"] = "iwasoverridden"
|
|
||||||
expectedMap["immaempty"] = ""
|
|
||||||
|
|
||||||
configMap, err := parseFile(configFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed while parsing the file")
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
flagMap := SetupFlagOverrides(configMap)
|
validateMap(t, conf, expectedMap)
|
||||||
|
|
||||||
err = flag.Set("foo.wat", "iwasoverridden")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to set cli flag override")
|
|
||||||
}
|
|
||||||
|
|
||||||
configMap = ParseFlags(configMap, flagMap)
|
|
||||||
|
|
||||||
validateMap(t, configMap, expectedMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseWithExtraQuotes(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
configFileStr := `
|
|
||||||
some.name = "This is in quotes"
|
|
||||||
extra.quotes = ""This will keep the quotes""
|
|
||||||
internal.quotes = "Some "thing" is here"
|
|
||||||
"This should work too" = shrug I guess
|
|
||||||
`
|
|
||||||
|
|
||||||
configFile := strings.NewReader(configFileStr)
|
|
||||||
|
|
||||||
expectedMap := make(ConfigMap)
|
|
||||||
expectedMap["some.name"] = "This is in quotes"
|
|
||||||
expectedMap["extra.quotes"] = "\"This will keep the quotes\""
|
|
||||||
expectedMap["internal.quotes"] = "Some \"thing\" is here"
|
|
||||||
expectedMap["This should work too"] = "shrug I guess"
|
|
||||||
|
|
||||||
configMap, err := parseFile(configFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed while parsing the file")
|
|
||||||
}
|
|
||||||
|
|
||||||
validateMap(t, configMap, expectedMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateMap(t *testing.T, given map[string]string, expected map[string]string) {
|
|
||||||
if given == nil {
|
|
||||||
t.Errorf("given map was nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
if expected == nil {
|
|
||||||
t.Errorf("expected map was nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedLen := len(expected)
|
|
||||||
givenLen := len(given)
|
|
||||||
if expectedLen != givenLen {
|
|
||||||
t.Errorf("size mismatch on maps - expected %v, given %v", expectedLen, givenLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range expected {
|
|
||||||
if v != given[k] {
|
|
||||||
t.Errorf("incorrect value for key %v - expected %v, given %v", k, expected[k], given[k])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
url = www.wisellama.rocks
|
||||||
|
number_of_widgets = 1337
|
||||||
|
pi = 3.141592653589793238462643383
|
||||||
|
environment = production
|
||||||
|
|
||||||
|
# Quotes are optional
|
||||||
|
name = Dude guy
|
||||||
|
description = "Just some dude it was"
|
||||||
|
|
||||||
|
# Additional equals are just part of the value
|
||||||
|
base64_tacos = dGFjb3M=
|
||||||
|
a=b=c
|
||||||
|
# key: 'a', value: 'b=c'
|
|
@ -0,0 +1,25 @@
|
||||||
|
package gosimpleconf
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func validateMap(t *testing.T, given map[string]string, expected map[string]string) {
|
||||||
|
if given == nil {
|
||||||
|
t.Errorf("given map was nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected == nil {
|
||||||
|
t.Errorf("expected map was nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedLen := len(expected)
|
||||||
|
givenLen := len(given)
|
||||||
|
if expectedLen != givenLen {
|
||||||
|
t.Errorf("size mismatch on maps - expected %v, given %v", expectedLen, givenLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range expected {
|
||||||
|
if v != given[k] {
|
||||||
|
t.Errorf("incorrect value for key %v - expected %v, given %v", k, expected[k], given[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue