Skip to content

Commit

Permalink
Merge pull request #24 from goreflect/issue_14
Browse files Browse the repository at this point in the history
Issue 14 Solved
  • Loading branch information
artemkaxboy committed Apr 9, 2020
2 parents ceaad54 + ec33120 commit 879e6b9
Show file tree
Hide file tree
Showing 17 changed files with 1,453 additions and 284 deletions.
110 changes: 54 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,86 @@
# Gostructor [![Actions Status](https://github.com/goreflect/gostructor/workflows/CI_dev/badge.svg)](https://github.com/goreflect/gostructor/actions?query=workflow%3ACI_dev) [![Go Report Card](https://goreportcard.com/badge/github.com/goreflect/gostructor)](https://goreportcard.com/report/github.com/goreflect/gostructor) [![codecov](https://codecov.io/gh/goreflect/gostructor/branch/master/graph/badge.svg)](https://codecov.io/gh/goreflect/gostructor)
____
### Version: 0.1.2
### Version: 0.4.1

hocon current configuration configuration library
Universal configuration library by tags

## Current supporting input formats

- hocon
- hocon values
- default values
- environment variables

## Current supporting types

- int32, int64
- int, int8, int16, int32, int64
- float32, float64
- string
- bool
- map[string\int]string\int\float32\float64
- slices of any types from (int32, int64, int, string, bool, float32, float64)

## Tags
### Tags

In current library using any of this tags:
- [x] cf_hocon - setup value for this field from hocon
- [x] cf_default - setup default value for this field
- [x] cf_env - setup value from env variable by name in this tag
- [ ] cf_yaml - setup value for this field from yaml (version > 0.6)
- [ ] cf_json - setup value for this field from json (version > 0.5)
- [ ] cf_server - setup value from configuration server like spring cloud config server or others (version>0.7)
- [ ] cf_vault - setup secret for this field from hashi corp vault (version>0.8)

1. cf_hocon - setup value for this field from hocon
2. cf_default - setup default value for this field
3. cf_env - setup value from env variable by name in this tag
4. cf_yaml - setup value for this field from yaml (version > 0.2)
5. cf_json - setup value for this field from json (version > 0.3)
6. cf_server - setup value from configuration server like spring cloud config server or others (version>0.4)
7. cf_vault - setup secret for this field from hashi corp vault (version>0.5)
## Running configuring by smart variant

## Validation(optional version > 0.6)
For Run configuration by smart variant autostart analysing of using tags. library will start configuring your structure by pipeline with all founded tags.

If you have validate your data you should write in source tag validate after comma and after : you can choose validation type:
- email
- phoneNumber8

## Menu

- [Reserved Tags](https://github.com/goreflect/gostructor/blob/master/tags)
- [Specifications](https://github.com/goreflect/gostructor/blob/master/specifications)

## Running configuring by easy way

For easy way you can chose gostructor.ConfigureEasy(). And if you have use one of file sources like: json, hocon, yaml, txt your files should ended by type (if your file not ended of type, this source will be ignored by function chainer)
```go
type Test struct {
MyValue1 string `cf_default:"turur" cf_hocon:"mySourceValue1"`
MySlice1 []bool `cf_default:"true,false,false,true" cf_env:"MY_SIGNALS"`
}

## Running configuring by setup way
// in this example do use 3 tags: cf_default (using default values which setup inline tag)
// cf_env - using environment variable
// cf_hocon - using hocon source file

For this way you should set up chain functions will used in configuring pipeline. For example:
`test.hocon`
```hocon
Examples = {
FieldExample = test1
//....

ExampleType = {
Field1 = test2
func myConfigurator() {
myStruct, errConfiguring := gostructir.ConfigureSmart(&Test{}, "testhocon.hocon")
// check errConfiguring for any errors
if errConfiguring != nil {
/// action for error
}
}
```

```golang
type ExampleType struct {
fieldTest1 string `cf_hocon:"Examples.FieldExample"`
Field1 string `cf_default:"tururutest"`
}
...
value, err := gostructor.ConfigureSetup(&ExampleType{}, "test.hocon", []pipeline.FuncType{
pipeline.FunctionSetupHocon,
pipeline.FunctionSetupDefault,
})
// cast interface{} into Test structure
myValues := myStruct.(*Test)
// now, u structure already filled
}

```

Where Value is Interface therefore you should cast to your type with Pointer like this:
```golang
value.(*ExampleType)
```
## Running configuring by setup

You can also setting configuring pipeline like this:

## Many examples
```go
type Test struct {
MyValue1 string `cf_default:"turur" cf_hocon:"mySourceValue1"`
MySlice1 []bool `cf_default:"true,false,false,true" cf_env:"MY_SIGNALS"`
}

In this section will added any examples of using this library
func myConfigurator() {
myStruct, errConfiguring := gostructir.ConfigureSetup(&Test{}, "testhocon.hocon", []infra.FuncType{
infra.FunctionSetupEnvironment,
})// you should setup only by order configure
// check errConfiguring for any errors
if errConfiguring != nil {
/// action for error
}

## TODO
// cast interface{} into Test structure
myValues := myStruct.(*Test)
// now, u structure already filled
}

1. Implement self converters for all sources
2. Write unit tests for any cases
3. Move getFieldName methods for any source func parsers because in any of source have available any naming sources
```
2 changes: 1 addition & 1 deletion converters/kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ ConvertBetweenComplexTypes - converting between complex types like slice to slic
*/
func ConvertBetweenComplexTypes(source reflect.Value, destination reflect.Value) infra.GoStructorValue {
switch destination.Kind() {
case reflect.Slice:
case reflect.Slice, reflect.Array:
return convertSlice(source, destination)
default:
return infra.NewGoStructorNoValue(destination, errors.New("not implemented"))
Expand Down
126 changes: 80 additions & 46 deletions lib_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gostructor

import (
"fmt"
"os"
"testing"

Expand All @@ -24,17 +23,17 @@ type (
MyMap map[int]string `cf_hocon:"MyMap"`
}

MyStruct3 struct {
NestedStruct2 struct {
Field1 string `cf_hocon:"test1"`
} `cf_hocon:"node=planB"`
}
// MyStruct3 struct {
// NestedStruct2 struct {
// Field1 string `cf_hocon:"test1"`
// } `cf_hocon:"node=planB"`
// }

MyStruct4 struct {
NestedStruct4 struct {
Field1 string
} `cf_hocon:"node=planC.tururu.tratatat.planZ"`
}
// MyStruct4 struct {
// NestedStruct4 struct {
// Field1 string
// } `cf_hocon:"node=planC.tururu.tratatat.planZ"`
// }

EnvStruct struct {
Field1 int16 `cf_env:"myField1"`
Expand All @@ -48,7 +47,8 @@ type (
func Test_parseHocon1(t *testing.T) {
myStruct, err := ConfigureSetup(&MyStruct{}, "./test_configs/test1.hocon", "", []infra.FuncType{infra.FunctionSetupHocon})
if err != nil {
t.Error("error while configuring: ", err)
t.Error("error while configurig: ", err)
return
}
assert.Equal(t, &MyStruct{
Field1: []string{"test1", "test2", "test3"},
Expand All @@ -62,6 +62,7 @@ func Test_parseHocon(t *testing.T) {
myStruct, err := ConfigureSetup(&MyStruct2{}, "./test_configs/testmap.hocon", "", []infra.FuncType{infra.FunctionSetupHocon})
if err != nil {
t.Error("error while configuring: ", err)
return
}
assert.Equal(t, &MyStruct2{
NestedStruct1: NestedStruct1{
Expand All @@ -75,45 +76,76 @@ func Test_parseHocon(t *testing.T) {
}, myStruct.(*MyStruct2))
}

func Test_parseHoconWithNodeNotation(t *testing.T) {
mystruct, err := ConfigureSetup(&MyStruct3{}, "./test_configs/testmap.hocon", "", []infra.FuncType{infra.FunctionSetupHocon})
if err != nil {
fmt.Println("error while configuring: ", err)
}
assert.Equal(t, &MyStruct3{
NestedStruct2: struct {
Field1 string "cf_hocon:\"test1\""
}{
Field1: "testValueByNodeInTag",
},
}, mystruct.(*MyStruct3))
}
// Depreacted because in pipeline can not supported node, path inline tag value
// func Test_parseHoconWithNodeNotation(t *testing.T) {
// mystruct, err := ConfigureSetup(&MyStruct3{}, "./test_configs/testmap.hocon", "", []infra.FuncType{infra.FunctionSetupHocon})
// if err != nil {
// fmt.Println("error while configuring: ", err)
// }
// assert.Equal(t, &MyStruct3{
// NestedStruct2: struct {
// Field1 string "cf_hocon:\"test1\""
// }{
// Field1: "testValueByNodeInTag",
// },
// }, mystruct.(*MyStruct3))
// }

func Test_parseHoconWithNodeNotation2(t *testing.T) {
myStruct, err := ConfigureSetup(&MyStruct4{}, "./test_configs/testmap.hocon", "", []infra.FuncType{infra.FunctionSetupHocon})
if err != nil {
fmt.Println("error while configuring: ", err)
}
assert.Equal(t, &MyStruct4{
NestedStruct4: struct{ Field1 string }{
Field1: "testValueByTest",
},
}, myStruct.(*MyStruct4))
}
// Depreacted because in pipeline can not supported node, path inline tag value
// func Test_parseHoconWithNodeNotation2(t *testing.T) {
// myStruct, err := ConfigureSetup(&MyStruct4{}, "./test_configs/testmap.hocon", "", []infra.FuncType{infra.FunctionSetupHocon})
// if err != nil {
// fmt.Println("error while configuring: ", err)
// }
// assert.Equal(t, &MyStruct4{
// NestedStruct4: struct{ Field1 string }{
// Field1: "testValueByTest",
// },
// }, myStruct.(*MyStruct4))
// }

// Depreacted because in pipeline can not supported node, path inline tag value
// func Test_smartConfigure(t *testing.T) {
// myStruct, err := ConfigureSmart(&MyStruct4{}, "./test_configs/testmap.hocon")
// if err != nil {
// fmt.Println("error while configuring: ", err)
// }
// assert.Equal(t, &MyStruct4{
// NestedStruct4: struct{ Field1 string }{
// Field1: "testValueByTest",
// },
// }, myStruct.(*MyStruct4))
// }

func Test_smartConfigure(t *testing.T) {
myStruct, err := ConfigureSmart(&MyStruct4{}, "./test_configs/testmap.hocon")
func Test_getValueFromEnvironment(t *testing.T) {
os.Setenv("myField1", "12")
os.Setenv("myField2", "test")
os.Setenv("myField3", "true")
os.Setenv("myField4", "12.2")
os.Setenv("myField5", "true,false,true")
defer func() {
os.Unsetenv("myField1")
os.Unsetenv("myField2")
os.Unsetenv("myField3")
os.Unsetenv("myField4")
os.Unsetenv("myField5")
}()
myStruct, err := ConfigureSmart(&EnvStruct{}, "")
if err != nil {
fmt.Println("error while configuring: ", err)
t.Error(err)
return
}
assert.Equal(t, &MyStruct4{
NestedStruct4: struct{ Field1 string }{
Field1: "testValueByTest",
},
}, myStruct.(*MyStruct4))

assert.Equal(t, &EnvStruct{
Field1: 12,
Field2: "test",
Field3: true,
Field4: 12.2,
Field5: []bool{true, false, true},
}, myStruct.(*EnvStruct))
}

func Test_getValueFromEnvironment(t *testing.T) {
func Test_configureEasy(t *testing.T) {
os.Setenv("myField1", "12")
os.Setenv("myField2", "test")
os.Setenv("myField3", "true")
Expand All @@ -126,9 +158,10 @@ func Test_getValueFromEnvironment(t *testing.T) {
os.Unsetenv("myField4")
os.Unsetenv("myField5")
}()
myStruct, err := ConfigureSmart(&EnvStruct{}, "")
myStruct, err := ConfigureEasy(&EnvStruct{}, "")
if err != nil {
t.Error(err)
return
}

assert.Equal(t, &EnvStruct{
Expand All @@ -138,4 +171,5 @@ func Test_getValueFromEnvironment(t *testing.T) {
Field4: 12.2,
Field5: []bool{true, false, true},
}, myStruct.(*EnvStruct))

}
43 changes: 43 additions & 0 deletions pipeline/files_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package pipeline

import "testing"

func Test_checkFileAccessibility(t *testing.T) {
type args struct {
filename string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "check permission denied",
args: args{
filename: "../test_configs/testFile",
},
wantErr: false,
},
{
name: "check derivet string is dir",
args: args{
filename: "../test_configs",
},
wantErr: true,
},
{
name: "check completed",
args: args{
filename: "../test_configs/testmap.hocon",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := checkFileAccessibility(tt.args.filename); (err != nil) != tt.wantErr {
t.Errorf("checkFileAccessibility() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
Loading

0 comments on commit 879e6b9

Please sign in to comment.