|  | // Copyright 2017 Frank Schroeder. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package properties | 
|  |  | 
|  | import ( | 
|  | "reflect" | 
|  | "testing" | 
|  | "time" | 
|  | ) | 
|  |  | 
|  | func TestDecodeValues(t *testing.T) { | 
|  | type S struct { | 
|  | S   string | 
|  | BT  bool | 
|  | BF  bool | 
|  | I   int | 
|  | I8  int8 | 
|  | I16 int16 | 
|  | I32 int32 | 
|  | I64 int64 | 
|  | U   uint | 
|  | U8  uint8 | 
|  | U16 uint16 | 
|  | U32 uint32 | 
|  | U64 uint64 | 
|  | F32 float32 | 
|  | F64 float64 | 
|  | D   time.Duration | 
|  | TM  time.Time | 
|  | } | 
|  | in := ` | 
|  | S=abc | 
|  | BT=true | 
|  | BF=false | 
|  | I=-1 | 
|  | I8=-8 | 
|  | I16=-16 | 
|  | I32=-32 | 
|  | I64=-64 | 
|  | U=1 | 
|  | U8=8 | 
|  | U16=16 | 
|  | U32=32 | 
|  | U64=64 | 
|  | F32=3.2 | 
|  | F64=6.4 | 
|  | D=5s | 
|  | TM=2015-01-02T12:34:56Z | 
|  | ` | 
|  | out := &S{ | 
|  | S:   "abc", | 
|  | BT:  true, | 
|  | BF:  false, | 
|  | I:   -1, | 
|  | I8:  -8, | 
|  | I16: -16, | 
|  | I32: -32, | 
|  | I64: -64, | 
|  | U:   1, | 
|  | U8:  8, | 
|  | U16: 16, | 
|  | U32: 32, | 
|  | U64: 64, | 
|  | F32: 3.2, | 
|  | F64: 6.4, | 
|  | D:   5 * time.Second, | 
|  | TM:  tm(t, time.RFC3339, "2015-01-02T12:34:56Z"), | 
|  | } | 
|  | testDecode(t, in, &S{}, out) | 
|  | } | 
|  |  | 
|  | func TestDecodeValueDefaults(t *testing.T) { | 
|  | type S struct { | 
|  | S   string        `properties:",default=abc"` | 
|  | BT  bool          `properties:",default=true"` | 
|  | BF  bool          `properties:",default=false"` | 
|  | I   int           `properties:",default=-1"` | 
|  | I8  int8          `properties:",default=-8"` | 
|  | I16 int16         `properties:",default=-16"` | 
|  | I32 int32         `properties:",default=-32"` | 
|  | I64 int64         `properties:",default=-64"` | 
|  | U   uint          `properties:",default=1"` | 
|  | U8  uint8         `properties:",default=8"` | 
|  | U16 uint16        `properties:",default=16"` | 
|  | U32 uint32        `properties:",default=32"` | 
|  | U64 uint64        `properties:",default=64"` | 
|  | F32 float32       `properties:",default=3.2"` | 
|  | F64 float64       `properties:",default=6.4"` | 
|  | D   time.Duration `properties:",default=5s"` | 
|  | TM  time.Time     `properties:",default=2015-01-02T12:34:56Z"` | 
|  | } | 
|  | out := &S{ | 
|  | S:   "abc", | 
|  | BT:  true, | 
|  | BF:  false, | 
|  | I:   -1, | 
|  | I8:  -8, | 
|  | I16: -16, | 
|  | I32: -32, | 
|  | I64: -64, | 
|  | U:   1, | 
|  | U8:  8, | 
|  | U16: 16, | 
|  | U32: 32, | 
|  | U64: 64, | 
|  | F32: 3.2, | 
|  | F64: 6.4, | 
|  | D:   5 * time.Second, | 
|  | TM:  tm(t, time.RFC3339, "2015-01-02T12:34:56Z"), | 
|  | } | 
|  | testDecode(t, "", &S{}, out) | 
|  | } | 
|  |  | 
|  | func TestDecodeArrays(t *testing.T) { | 
|  | type S struct { | 
|  | S   []string | 
|  | B   []bool | 
|  | I   []int | 
|  | I8  []int8 | 
|  | I16 []int16 | 
|  | I32 []int32 | 
|  | I64 []int64 | 
|  | U   []uint | 
|  | U8  []uint8 | 
|  | U16 []uint16 | 
|  | U32 []uint32 | 
|  | U64 []uint64 | 
|  | F32 []float32 | 
|  | F64 []float64 | 
|  | D   []time.Duration | 
|  | TM  []time.Time | 
|  | } | 
|  | in := ` | 
|  | S=a;b | 
|  | B=true;false | 
|  | I=-1;-2 | 
|  | I8=-8;-9 | 
|  | I16=-16;-17 | 
|  | I32=-32;-33 | 
|  | I64=-64;-65 | 
|  | U=1;2 | 
|  | U8=8;9 | 
|  | U16=16;17 | 
|  | U32=32;33 | 
|  | U64=64;65 | 
|  | F32=3.2;3.3 | 
|  | F64=6.4;6.5 | 
|  | D=4s;5s | 
|  | TM=2015-01-01T00:00:00Z;2016-01-01T00:00:00Z | 
|  | ` | 
|  | out := &S{ | 
|  | S:   []string{"a", "b"}, | 
|  | B:   []bool{true, false}, | 
|  | I:   []int{-1, -2}, | 
|  | I8:  []int8{-8, -9}, | 
|  | I16: []int16{-16, -17}, | 
|  | I32: []int32{-32, -33}, | 
|  | I64: []int64{-64, -65}, | 
|  | U:   []uint{1, 2}, | 
|  | U8:  []uint8{8, 9}, | 
|  | U16: []uint16{16, 17}, | 
|  | U32: []uint32{32, 33}, | 
|  | U64: []uint64{64, 65}, | 
|  | F32: []float32{3.2, 3.3}, | 
|  | F64: []float64{6.4, 6.5}, | 
|  | D:   []time.Duration{4 * time.Second, 5 * time.Second}, | 
|  | TM:  []time.Time{tm(t, time.RFC3339, "2015-01-01T00:00:00Z"), tm(t, time.RFC3339, "2016-01-01T00:00:00Z")}, | 
|  | } | 
|  | testDecode(t, in, &S{}, out) | 
|  | } | 
|  |  | 
|  | func TestDecodeArrayDefaults(t *testing.T) { | 
|  | type S struct { | 
|  | S   []string        `properties:",default=a;b"` | 
|  | B   []bool          `properties:",default=true;false"` | 
|  | I   []int           `properties:",default=-1;-2"` | 
|  | I8  []int8          `properties:",default=-8;-9"` | 
|  | I16 []int16         `properties:",default=-16;-17"` | 
|  | I32 []int32         `properties:",default=-32;-33"` | 
|  | I64 []int64         `properties:",default=-64;-65"` | 
|  | U   []uint          `properties:",default=1;2"` | 
|  | U8  []uint8         `properties:",default=8;9"` | 
|  | U16 []uint16        `properties:",default=16;17"` | 
|  | U32 []uint32        `properties:",default=32;33"` | 
|  | U64 []uint64        `properties:",default=64;65"` | 
|  | F32 []float32       `properties:",default=3.2;3.3"` | 
|  | F64 []float64       `properties:",default=6.4;6.5"` | 
|  | D   []time.Duration `properties:",default=4s;5s"` | 
|  | TM  []time.Time     `properties:",default=2015-01-01T00:00:00Z;2016-01-01T00:00:00Z"` | 
|  | } | 
|  | out := &S{ | 
|  | S:   []string{"a", "b"}, | 
|  | B:   []bool{true, false}, | 
|  | I:   []int{-1, -2}, | 
|  | I8:  []int8{-8, -9}, | 
|  | I16: []int16{-16, -17}, | 
|  | I32: []int32{-32, -33}, | 
|  | I64: []int64{-64, -65}, | 
|  | U:   []uint{1, 2}, | 
|  | U8:  []uint8{8, 9}, | 
|  | U16: []uint16{16, 17}, | 
|  | U32: []uint32{32, 33}, | 
|  | U64: []uint64{64, 65}, | 
|  | F32: []float32{3.2, 3.3}, | 
|  | F64: []float64{6.4, 6.5}, | 
|  | D:   []time.Duration{4 * time.Second, 5 * time.Second}, | 
|  | TM:  []time.Time{tm(t, time.RFC3339, "2015-01-01T00:00:00Z"), tm(t, time.RFC3339, "2016-01-01T00:00:00Z")}, | 
|  | } | 
|  | testDecode(t, "", &S{}, out) | 
|  | } | 
|  |  | 
|  | func TestDecodeSkipUndef(t *testing.T) { | 
|  | type S struct { | 
|  | X     string `properties:"-"` | 
|  | Undef string `properties:",default=some value"` | 
|  | } | 
|  | in := `X=ignore` | 
|  | out := &S{"", "some value"} | 
|  | testDecode(t, in, &S{}, out) | 
|  | } | 
|  |  | 
|  | func TestDecodeStruct(t *testing.T) { | 
|  | type A struct { | 
|  | S string | 
|  | T string `properties:"t"` | 
|  | U string `properties:"u,default=uuu"` | 
|  | } | 
|  | type S struct { | 
|  | A A | 
|  | B A `properties:"b"` | 
|  | } | 
|  | in := ` | 
|  | A.S=sss | 
|  | A.t=ttt | 
|  | b.S=SSS | 
|  | b.t=TTT | 
|  | ` | 
|  | out := &S{ | 
|  | A{S: "sss", T: "ttt", U: "uuu"}, | 
|  | A{S: "SSS", T: "TTT", U: "uuu"}, | 
|  | } | 
|  | testDecode(t, in, &S{}, out) | 
|  | } | 
|  |  | 
|  | func TestDecodeMap(t *testing.T) { | 
|  | type S struct { | 
|  | A string `properties:"a"` | 
|  | } | 
|  | type X struct { | 
|  | A map[string]string | 
|  | B map[string][]string | 
|  | C map[string]map[string]string | 
|  | D map[string]S | 
|  | E map[string]int | 
|  | F map[string]int `properties:"-"` | 
|  | } | 
|  | in := ` | 
|  | A.foo=bar | 
|  | A.bar=bang | 
|  | B.foo=a;b;c | 
|  | B.bar=1;2;3 | 
|  | C.foo.one=1 | 
|  | C.foo.two=2 | 
|  | C.bar.three=3 | 
|  | C.bar.four=4 | 
|  | D.foo.a=bar | 
|  | ` | 
|  | out := &X{ | 
|  | A: map[string]string{"foo": "bar", "bar": "bang"}, | 
|  | B: map[string][]string{"foo": []string{"a", "b", "c"}, "bar": []string{"1", "2", "3"}}, | 
|  | C: map[string]map[string]string{"foo": map[string]string{"one": "1", "two": "2"}, "bar": map[string]string{"three": "3", "four": "4"}}, | 
|  | D: map[string]S{"foo": S{"bar"}}, | 
|  | E: map[string]int{}, | 
|  | } | 
|  | testDecode(t, in, &X{}, out) | 
|  | } | 
|  |  | 
|  | func testDecode(t *testing.T, in string, v, out interface{}) { | 
|  | p, err := parse(in) | 
|  | if err != nil { | 
|  | t.Fatalf("got %v want nil", err) | 
|  | } | 
|  | if err := p.Decode(v); err != nil { | 
|  | t.Fatalf("got %v want nil", err) | 
|  | } | 
|  | if got, want := v, out; !reflect.DeepEqual(got, want) { | 
|  | t.Fatalf("\ngot  %+v\nwant %+v", got, want) | 
|  | } | 
|  | } | 
|  |  | 
|  | func tm(t *testing.T, layout, s string) time.Time { | 
|  | tm, err := time.Parse(layout, s) | 
|  | if err != nil { | 
|  | t.Fatalf("got %v want nil", err) | 
|  | } | 
|  | return tm | 
|  | } |