package scfg_test import ( "fmt" "log" "reflect" "strings" "testing" "go.lindenii.runxiyu.org/lindenii-common/scfg" ) func ExampleDecoder() { var data struct { Foo int `scfg:"foo"` Bar struct { Param string `scfg:",param"` Baz string `scfg:"baz"` } `scfg:"bar"` } raw := `foo 42 bar asdf { baz hello } ` r := strings.NewReader(raw) if err := scfg.NewDecoder(r).Decode(&data); err != nil { log.Fatal(err) } fmt.Printf("Foo = %v\n", data.Foo) fmt.Printf("Bar.Param = %v\n", data.Bar.Param) fmt.Printf("Bar.Baz = %v\n", data.Bar.Baz) // Output: // Foo = 42 // Bar.Param = asdf // Bar.Baz = hello } type nestedStructInner struct { Bar string `scfg:"bar"` } type structParams struct { Params []string `scfg:",param"` Bar string } type textUnmarshaler struct { text string } func (tu *textUnmarshaler) UnmarshalText(text []byte) error { tu.text = string(text) return nil } type textUnmarshalerParams struct { Params []textUnmarshaler `scfg:",param"` } var barStr = "bar" var unmarshalTests = []struct { name string raw string want interface{} }{ { name: "stringMap", raw: `hello world foo bar`, want: map[string]string{ "hello": "world", "foo": "bar", }, }, { name: "simpleStruct", raw: `MyString asdf MyBool true MyInt -42 MyUint 42 MyFloat 3.14`, want: struct { MyString string MyBool bool MyInt int MyUint uint MyFloat float32 }{ MyString: "asdf", MyBool: true, MyInt: -42, MyUint: 42, MyFloat: 3.14, }, }, { name: "simpleStructTag", raw: `foo bar`, want: struct { Foo string `scfg:"foo"` }{ Foo: "bar", }, }, { name: "sliceParams", raw: `Foo a s d f`, want: struct { Foo []string }{ Foo: []string{"a", "s", "d", "f"}, }, }, { name: "arrayParams", raw: `Foo a s d f`, want: struct { Foo [4]string }{ Foo: [4]string{"a", "s", "d", "f"}, }, }, { name: "pointers", raw: `Foo bar`, want: struct { Foo *string }{ Foo: &barStr, }, }, { name: "nestedMap", raw: `foo { bar baz }`, want: struct { Foo map[string]string `scfg:"foo"` }{ Foo: map[string]string{"bar": "baz"}, }, }, { name: "nestedStruct", raw: `foo { bar baz }`, want: struct { Foo nestedStructInner `scfg:"foo"` }{ Foo: nestedStructInner{ Bar: "baz", }, }, }, { name: "structParams", raw: `Foo param1 param2 { Bar baz }`, want: struct { Foo structParams }{ Foo: structParams{ Params: []string{"param1", "param2"}, Bar: "baz", }, }, }, { name: "textUnmarshaler", raw: `Foo param1 Bar param2 Baz param3`, want: struct { Foo []textUnmarshaler Bar *textUnmarshaler Baz textUnmarshalerParams }{ Foo: []textUnmarshaler{{"param1"}}, Bar: &textUnmarshaler{"param2"}, Baz: textUnmarshalerParams{ Params: []textUnmarshaler{{"param3"}}, }, }, }, { name: "directiveStructSlice", raw: `Foo param1 param2 { Bar baz } Foo param3 param4`, want: struct { Foo []structParams }{ Foo: []structParams{ { Params: []string{"param1", "param2"}, Bar: "baz", }, { Params: []string{"param3", "param4"}, }, }, }, }, { name: "directiveMapSlice", raw: `Foo { key1 param1 } Foo { key2 param2 }`, want: struct { Foo []map[string]string }{ Foo: []map[string]string{ {"key1": "param1"}, {"key2": "param2"}, }, }, }, } func TestUnmarshal(t *testing.T) { for _, tc := range unmarshalTests { tc := tc // capture variable t.Run(tc.name, func(t *testing.T) { testUnmarshal(t, tc.raw, tc.want) }) } } func testUnmarshal(t *testing.T, raw string, want interface{}) { out := reflect.New(reflect.TypeOf(want)) r := strings.NewReader(raw) if err := scfg.NewDecoder(r).Decode(out.Interface()); err != nil { t.Fatalf("Decode() = %v", err) } got := out.Elem().Interface() if !reflect.DeepEqual(got, want) { t.Errorf("Decode() = \n%#v\n but want \n%#v", got, want) } }