forked from TrueCloudLab/restic
options: Add Apply()
This commit is contained in:
parent
f587a5f4f0
commit
2924ebc124
2 changed files with 156 additions and 0 deletions
|
@ -1,8 +1,11 @@
|
|||
package options
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"restic/errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Options holds options in the form key=value.
|
||||
|
@ -64,3 +67,59 @@ func (o Options) Extract(ns string) Options {
|
|||
|
||||
return opts
|
||||
}
|
||||
|
||||
// Apply sets the options on dst via reflection, using the struct tag `option`.
|
||||
func (o Options) Apply(dst interface{}) error {
|
||||
v := reflect.ValueOf(dst).Elem()
|
||||
|
||||
fields := make(map[string]reflect.StructField)
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
f := v.Type().Field(i)
|
||||
tag := f.Tag.Get("option")
|
||||
|
||||
if tag == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := fields[tag]; ok {
|
||||
panic("option tag " + tag + " is not unique in " + v.Type().Name())
|
||||
}
|
||||
|
||||
fields[tag] = f
|
||||
}
|
||||
|
||||
for key, value := range o {
|
||||
field, ok := fields[key]
|
||||
if !ok {
|
||||
return errors.Fatalf("option %v is not known", key)
|
||||
}
|
||||
|
||||
i := field.Index[0]
|
||||
switch v.Type().Field(i).Type.Name() {
|
||||
case "string":
|
||||
v.Field(i).SetString(value)
|
||||
|
||||
case "int":
|
||||
vi, err := strconv.ParseInt(value, 0, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.Field(i).SetInt(vi)
|
||||
|
||||
case "Duration":
|
||||
d, err := time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.Field(i).SetInt(int64(d))
|
||||
|
||||
default:
|
||||
panic("type " + v.Type().Field(i).Type.Name() + " not handled")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var optsTests = []struct {
|
||||
|
@ -117,3 +118,99 @@ func TestOptionsExtract(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Target is used for Apply() tests
|
||||
type Target struct {
|
||||
Name string `option:"name"`
|
||||
ID int `option:"id"`
|
||||
Timeout time.Duration `option:"timeout"`
|
||||
Other string
|
||||
}
|
||||
|
||||
var setTests = []struct {
|
||||
input Options
|
||||
output Target
|
||||
}{
|
||||
{
|
||||
Options{
|
||||
"name": "foobar",
|
||||
},
|
||||
Target{
|
||||
Name: "foobar",
|
||||
},
|
||||
},
|
||||
{
|
||||
Options{
|
||||
"name": "foobar",
|
||||
"id": "1234",
|
||||
},
|
||||
Target{
|
||||
Name: "foobar",
|
||||
ID: 1234,
|
||||
},
|
||||
},
|
||||
{
|
||||
Options{
|
||||
"timeout": "10m3s",
|
||||
},
|
||||
Target{
|
||||
Timeout: time.Duration(10*time.Minute + 3*time.Second),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestOptionsApply(t *testing.T) {
|
||||
for i, test := range setTests {
|
||||
t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) {
|
||||
var dst Target
|
||||
err := test.input.Apply(&dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if dst != test.output {
|
||||
t.Fatalf("wrong result, want:\n %#v\ngot:\n %#v", test.output, dst)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var invalidSetTests = []struct {
|
||||
input Options
|
||||
err string
|
||||
}{
|
||||
{
|
||||
Options{
|
||||
"first_name": "foobar",
|
||||
},
|
||||
"option first_name is not known",
|
||||
},
|
||||
{
|
||||
Options{
|
||||
"id": "foobar",
|
||||
},
|
||||
`strconv.ParseInt: parsing "foobar": invalid syntax`,
|
||||
},
|
||||
{
|
||||
Options{
|
||||
"timeout": "2134",
|
||||
},
|
||||
`time: missing unit in duration 2134`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestOptionsApplyInvalid(t *testing.T) {
|
||||
for i, test := range invalidSetTests {
|
||||
t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) {
|
||||
var dst Target
|
||||
err := test.input.Apply(&dst)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error %v not found", test.err)
|
||||
}
|
||||
|
||||
if err.Error() != test.err {
|
||||
t.Fatalf("expected error %q, got %q", test.err, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue