Skip to content

Commit dec5825

Browse files
author
Lucas Baldoni
committed
Removed write quote in marshal to allow write other types than strings
1 parent 87b9f05 commit dec5825

File tree

3 files changed

+227
-7
lines changed

3 files changed

+227
-7
lines changed

custom_marshaler_test.go

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
package toml_test
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"fmt"
7+
"github.com/BurntSushi/toml"
8+
"strconv"
9+
"strings"
10+
"testing"
11+
)
12+
13+
// Test for hotfix-341
14+
func TestCustomEncode(t *testing.T) {
15+
16+
var enum = Enum(OtherValue)
17+
18+
outer := Outer{
19+
String: &InnerString{value: "value"},
20+
Int: &InnerInt{value: 10},
21+
Bool: &InnerBool{value: true},
22+
Enum: &enum,
23+
ArrayS: &InnerArrayString{value: []string{"text1", "text2"}},
24+
ArrayI: &InnerArrayInt{value: []int64{5, 7, 3}},
25+
}
26+
27+
var buf bytes.Buffer
28+
err := toml.NewEncoder(&buf).Encode(outer)
29+
if err != nil {
30+
t.Errorf("Encode failed: %s", err)
31+
}
32+
33+
have := strings.TrimSpace(buf.String())
34+
want := strings.TrimSpace("String = \"value\"\nInt = 10\nBool = true\nEnum = \"OTHER_VALUE\"\nArrayS = [\"text1\", \"text2\"]\nArrayI = [5, 7, 3]\n")
35+
if want != have {
36+
t.Errorf("\nhave:\n%s\nwant:\n%s\n", have, want)
37+
}
38+
}
39+
40+
// Test for hotfix-341
41+
func TestCustomDecode(t *testing.T) {
42+
43+
const testToml = "Bool = true\nString = \"test\"\nInt = 10\nEnum = \"OTHER_VALUE\"\nArrayS = [\"text1\", \"text2\"]\nArrayI = [5, 7, 3]"
44+
45+
outer := Outer{}
46+
_, err := toml.Decode(testToml, &outer)
47+
48+
if err != nil {
49+
t.Fatal(fmt.Sprintf("Decode failed: %s", err))
50+
}
51+
if outer.String.value != "test" {
52+
t.Errorf("\nhave:\n%s\nwant:\n%s\n", outer.String.value, "test")
53+
}
54+
if outer.Bool.value != true {
55+
t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.Bool.value, true)
56+
}
57+
if outer.Int.value != 10 {
58+
t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.Int.value, 10)
59+
}
60+
61+
if *outer.Enum != OtherValue {
62+
t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.Enum, OtherValue)
63+
}
64+
if fmt.Sprint(outer.ArrayS.value) != fmt.Sprint([]string{"text1", "text2"}) {
65+
t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.ArrayS.value, []string{"text1", "text2"})
66+
}
67+
if fmt.Sprint(outer.ArrayI.value) != fmt.Sprint([]int64{5, 7, 3}) {
68+
t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.ArrayI.value, []int64{5, 7, 3})
69+
}
70+
}
71+
72+
/* Implementing MarshalTOML and UnmarshalTOML structs
73+
An useful use could be to map a TOML value to an internal value, like emuns.
74+
*/
75+
76+
type Enum int
77+
78+
const (
79+
NoValue Enum = iota
80+
SomeValue
81+
OtherValue
82+
)
83+
84+
func (e *Enum) Value() string {
85+
switch *e {
86+
case SomeValue:
87+
return "SOME_VALUE"
88+
case OtherValue:
89+
return "OTHER_VALUE"
90+
case NoValue:
91+
return ""
92+
}
93+
return ""
94+
}
95+
96+
func (e *Enum) MarshalTOML() ([]byte, error) {
97+
return []byte("\"" + e.Value() + "\""), nil
98+
}
99+
100+
func (e *Enum) UnmarshalTOML(value interface{}) error {
101+
sValue, ok := value.(string)
102+
if !ok {
103+
return fmt.Errorf("value %v is not a string type", value)
104+
}
105+
for _, enum := range []Enum{NoValue, SomeValue, OtherValue} {
106+
if enum.Value() == sValue {
107+
*e = enum
108+
return nil
109+
}
110+
}
111+
return errors.New("invalid enum value")
112+
}
113+
114+
type InnerString struct {
115+
value string
116+
}
117+
118+
func (s *InnerString) MarshalTOML() ([]byte, error) {
119+
return []byte("\"" + s.value + "\""), nil
120+
}
121+
func (s *InnerString) UnmarshalTOML(value interface{}) error {
122+
sValue, ok := value.(string)
123+
if !ok {
124+
return fmt.Errorf("value %v is not a string type", value)
125+
}
126+
s.value = sValue
127+
return nil
128+
}
129+
130+
type InnerInt struct {
131+
value int
132+
}
133+
134+
func (i *InnerInt) MarshalTOML() ([]byte, error) {
135+
return []byte(strconv.Itoa(i.value)), nil
136+
}
137+
func (i *InnerInt) UnmarshalTOML(value interface{}) error {
138+
iValue, ok := value.(int64)
139+
if !ok {
140+
return fmt.Errorf("value %v is not a int type", value)
141+
}
142+
i.value = int(iValue)
143+
return nil
144+
}
145+
146+
type InnerBool struct {
147+
value bool
148+
}
149+
150+
func (b *InnerBool) MarshalTOML() ([]byte, error) {
151+
return []byte(strconv.FormatBool(b.value)), nil
152+
}
153+
func (b *InnerBool) UnmarshalTOML(value interface{}) error {
154+
bValue, ok := value.(bool)
155+
if !ok {
156+
return fmt.Errorf("value %v is not a bool type", value)
157+
}
158+
b.value = bValue
159+
return nil
160+
}
161+
162+
163+
type InnerArrayString struct {
164+
value []string
165+
}
166+
167+
func (as *InnerArrayString) MarshalTOML() ([]byte, error) {
168+
return []byte("[\"" + strings.Join(as.value, "\", \"") + "\"]"), nil
169+
}
170+
171+
func (as *InnerArrayString) UnmarshalTOML(value interface{}) error {
172+
if value != nil {
173+
asValue, ok := value.([]interface{})
174+
if !ok {
175+
return fmt.Errorf("value %v is not a [] type", value)
176+
}
177+
as.value = []string{}
178+
for _, value := range asValue {
179+
as.value = append(as.value, value.(string))
180+
}
181+
}
182+
return nil
183+
}
184+
185+
type InnerArrayInt struct {
186+
value []int64
187+
}
188+
189+
func (ai *InnerArrayInt) MarshalTOML() ([]byte, error) {
190+
strArr := []string{}
191+
for _, intV := range ai.value {
192+
strArr = append(strArr, strconv.FormatInt(intV, 10))
193+
}
194+
return []byte("[" + strings.Join(strArr, ", ") + "]"), nil
195+
}
196+
197+
func (ai *InnerArrayInt) UnmarshalTOML(value interface{}) error {
198+
if value != nil {
199+
asValue, ok := value.([]interface{})
200+
if !ok {
201+
return fmt.Errorf("value %v is not a [] type", value)
202+
}
203+
ai.value = []int64{}
204+
for _, value := range asValue {
205+
ai.value = append(ai.value, value.(int64))
206+
}
207+
}
208+
return nil
209+
}
210+
211+
type Outer struct {
212+
String *InnerString
213+
Int *InnerInt
214+
Bool *InnerBool
215+
Enum *Enum
216+
ArrayS *InnerArrayString
217+
ArrayI *InnerArrayInt
218+
}

encode.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func (enc *Encoder) eElement(rv reflect.Value) {
212212
if err != nil {
213213
encPanic(err)
214214
}
215-
enc.writeQuoted(string(s))
215+
enc.w.Write(s)
216216
return
217217
case encoding.TextMarshaler:
218218
s, err := v.MarshalText()

encode_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -347,12 +347,14 @@ func (c cplx) MarshalText() ([]byte, error) {
347347
return []byte(fmt.Sprintf("(%f+%fi)", real(cplx), imag(cplx))), nil
348348
}
349349

350-
func (s *sound2) MarshalTOML() ([]byte, error) { return []byte(s.S), nil }
351-
func (f food2) MarshalTOML() ([]byte, error) { return []byte(strings.Join(f.F, ", ")), nil }
352-
func (f fun2) MarshalTOML() ([]byte, error) { return []byte("why would you do this?"), nil }
350+
func (s *sound2) MarshalTOML() ([]byte, error) { return []byte("\"" + s.S + "\""), nil }
351+
func (f food2) MarshalTOML() ([]byte, error) {
352+
return []byte("[\"" + strings.Join(f.F, "\", \"") + "\"]"), nil
353+
}
354+
func (f fun2) MarshalTOML() ([]byte, error) { return []byte("\"why would you do this?\""), nil }
353355
func (c cplx2) MarshalTOML() ([]byte, error) {
354356
cplx := complex128(c)
355-
return []byte(fmt.Sprintf("(%f+%fi)", real(cplx), imag(cplx))), nil
357+
return []byte(fmt.Sprintf("\"(%f+%fi)\"", real(cplx), imag(cplx))), nil
356358
}
357359

358360
func TestEncodeTextMarshaler(t *testing.T) {
@@ -435,8 +437,8 @@ func TestEncodeTOMLMarshaler(t *testing.T) {
435437

436438
want := `Name = "Goblok"
437439
Sound2 = "miauw"
438-
Food = "chicken, fish"
439-
Food2 = "chicken, fish"
440+
Food = ["chicken", "fish"]
441+
Food2 = ["chicken", "fish"]
440442
Complex = "(42.000000+666.000000i)"
441443
Fun = "why would you do this?"
442444

0 commit comments

Comments
 (0)