all repos

json2go @ v0.2.2

convert json to go type annotations

json2go/transpiler_test.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
refactor!: inline all nested types, 19 days ago
1
package json2go
2
3
import (
4
	"strings"
5
	"testing"
6
)
7
8
func TestTranspiler_Transpile_WithTags(t *testing.T) {
9
	tests := map[string]struct {
10
		v     Value
11
		name  string
12
		check func(t *testing.T, result string)
13
	}{
14
		"simple object": {
15
			name: "User",
16
			v: Value{
17
				Kind: ObjectValue,
18
				Object: []Field{
19
					{K: "name", V: Value{Kind: StringValue, Str: "John"}},
20
					{K: "age", V: Value{Kind: NumberValue, Int: 30}},
21
				},
22
			},
23
			check: func(t *testing.T, result string) {
24
				if !strings.Contains(result, "type User struct") {
25
					t.Errorf("missing User struct")
26
				}
27
				if !strings.Contains(result, "Name string `json:\"name\"`") {
28
					t.Errorf("missing Name field")
29
				}
30
				if !strings.Contains(result, "Age int `json:\"age\"`") {
31
					t.Errorf("missing Age field")
32
				}
33
			},
34
		},
35
		"nested object": {
36
			name: "Response",
37
			v: Value{
38
				Kind: ObjectValue,
39
				Object: []Field{{
40
					K: "user",
41
					V: Value{
42
						Kind: ObjectValue,
43
						Object: []Field{
44
							{K: "name", V: Value{Kind: StringValue, Str: "Alice"}},
45
							{K: "active", V: Value{Kind: BoolValue, Bool: true}},
46
						},
47
					},
48
				}},
49
			},
50
			check: func(t *testing.T, result string) {
51
				if !strings.Contains(result, "type Response struct") {
52
					t.Errorf("missing Response struct")
53
				}
54
				if !strings.Contains(result, "Name string `json:\"name\"`") {
55
					t.Errorf("missing Name field")
56
				}
57
				if !strings.Contains(result, "Active bool `json:\"active\"`") {
58
					t.Errorf("missing Active field")
59
				}
60
				if !strings.Contains(result, "User struct {") {
61
					t.Errorf("missing inline User struct")
62
				}
63
			},
64
		},
65
		"array of scalars": {
66
			name: "Tags",
67
			v: Value{
68
				Kind:  ArrayValue,
69
				Array: []Value{{Kind: StringValue, Str: "go"}},
70
			},
71
			check: func(t *testing.T, result string) {
72
				if result != "type Tags []string" {
73
					t.Errorf("expected scalar array type, got: %s", result)
74
				}
75
			},
76
		},
77
		"array of objects": {
78
			name: "Users",
79
			v: Value{
80
				Kind: ArrayValue,
81
				Array: []Value{{
82
					Kind: ObjectValue,
83
					Object: []Field{
84
						{K: "id", V: Value{Kind: NumberValue, Int: 1}},
85
						{K: "name", V: Value{Kind: StringValue, Str: "Bob"}},
86
					},
87
				}},
88
			},
89
			check: func(t *testing.T, result string) {
90
				if !strings.Contains(result, "type Users []struct {") {
91
					t.Errorf("missing Users array type with inline struct, got: %s", result)
92
				}
93
				if !strings.Contains(result, "Id int `json:\"id\"`") {
94
					t.Errorf("missing Id field")
95
				}
96
			},
97
		},
98
		"snake_case fields": {
99
			name: "Data",
100
			v: Value{
101
				Kind: ObjectValue,
102
				Object: []Field{
103
					{K: "first_name", V: Value{Kind: StringValue, Str: "Jane"}},
104
					{K: "last_name", V: Value{Kind: StringValue, Str: "Doe"}},
105
				},
106
			},
107
			check: func(t *testing.T, result string) {
108
				if !strings.Contains(result, "FirstName string `json:\"first_name\"`") {
109
					t.Errorf("missing FirstName field")
110
				}
111
				if !strings.Contains(result, "LastName string `json:\"last_name\"`") {
112
					t.Errorf("missing LastName field")
113
				}
114
			},
115
		},
116
	}
117
	for tname, tt := range tests {
118
		t.Run(tname, func(t *testing.T) {
119
			result, err := NewTranspiler().Transpile(tt.name, tt.v, true)
120
			if err != nil {
121
				t.Fatalf("unexpected error: %v", err)
122
			}
123
			tt.check(t, result)
124
		})
125
	}
126
}
127
128
func TestTranspiler_Transpile_WithoutTags(t *testing.T) {
129
	tests := map[string]struct {
130
		v     Value
131
		name  string
132
		check func(t *testing.T, result string)
133
	}{
134
		"simple object": {
135
			name: "User",
136
			v: Value{
137
				Kind: ObjectValue,
138
				Object: []Field{
139
					{K: "name", V: Value{Kind: StringValue, Str: "John"}},
140
					{K: "age", V: Value{Kind: NumberValue, Int: 30}},
141
				},
142
			},
143
			check: func(t *testing.T, result string) {
144
				if !strings.Contains(result, "type User struct") {
145
					t.Errorf("missing User struct")
146
				}
147
				if !strings.Contains(result, "Name string\n") {
148
					t.Errorf("missing Name field without tag")
149
				}
150
				if !strings.Contains(result, "Age int\n") {
151
					t.Errorf("missing Age field without tag")
152
				}
153
				if strings.Contains(result, "`json:") {
154
					t.Errorf("should not have json tags")
155
				}
156
			},
157
		},
158
		"nested object": {
159
			name: "Response",
160
			v: Value{
161
				Kind: ObjectValue,
162
				Object: []Field{{
163
					K: "user",
164
					V: Value{
165
						Kind: ObjectValue,
166
						Object: []Field{
167
							{K: "name", V: Value{Kind: StringValue, Str: "Alice"}},
168
							{K: "active", V: Value{Kind: BoolValue, Bool: true}},
169
						},
170
					},
171
				}},
172
			},
173
			check: func(t *testing.T, result string) {
174
				if !strings.Contains(result, "type Response struct") {
175
					t.Errorf("missing Response struct")
176
				}
177
				if !strings.Contains(result, "User struct {") {
178
					t.Errorf("missing inline User struct")
179
				}
180
				if !strings.Contains(result, "Name string\n") {
181
					t.Errorf("missing Name field")
182
				}
183
				if !strings.Contains(result, "Active bool\n") {
184
					t.Errorf("missing Active field")
185
				}
186
				if strings.Contains(result, "`json:") {
187
					t.Errorf("should not have json tags")
188
				}
189
			},
190
		},
191
		"snake_case fields preserved": {
192
			name: "Data",
193
			v: Value{
194
				Kind: ObjectValue,
195
				Object: []Field{
196
					{K: "first_name", V: Value{Kind: StringValue, Str: "Jane"}},
197
					{K: "last_name", V: Value{Kind: StringValue, Str: "Doe"}},
198
				},
199
			},
200
			check: func(t *testing.T, result string) {
201
				if !strings.Contains(result, "FirstName string\n") {
202
					t.Errorf("missing FirstName field")
203
				}
204
				if !strings.Contains(result, "LastName string\n") {
205
					t.Errorf("missing LastName field")
206
				}
207
			},
208
		},
209
	}
210
	for tname, tt := range tests {
211
		t.Run(tname, func(t *testing.T) {
212
			result, err := NewTranspiler().Transpile(tt.name, tt.v, false)
213
			if err != nil {
214
				t.Fatalf("unexpected error: %v", err)
215
			}
216
			tt.check(t, result)
217
		})
218
	}
219
}
220
221
func TestTranspiler_ParserIntegration(t *testing.T) {
222
	tests := map[string]struct {
223
		input       string
224
		structName  string
225
		includeTags bool
226
		expectTags  bool
227
	}{
228
		"parse and transpile with tags": {
229
			input:       `{"user_name": "alice", "user_age": 25}`,
230
			structName:  "Profile",
231
			includeTags: true,
232
			expectTags:  true,
233
		},
234
		"parse and transpile without tags": {
235
			input:       `{"user_name": "bob", "user_age": 30}`,
236
			structName:  "Account",
237
			includeTags: false,
238
			expectTags:  false,
239
		},
240
	}
241
	for tname, tt := range tests {
242
		t.Run(tname, func(t *testing.T) {
243
			lexer := NewLexer([]byte(tt.input))
244
			parser := NewParser(lexer)
245
			v, err := parser.Parse()
246
			if err != nil {
247
				t.Fatalf("parse error: %v", err)
248
			}
249
250
			result, err := NewTranspiler().Transpile(tt.structName, v, tt.includeTags)
251
			if err != nil {
252
				t.Fatalf("transpile error: %v", err)
253
			}
254
255
			hasTag := strings.Contains(result, "`json:")
256
			if tt.expectTags != hasTag {
257
				t.Errorf("expected tags=%v, got=%v\n%s", tt.expectTags, hasTag, result)
258
			}
259
260
			if !strings.Contains(result, "type "+tt.structName) {
261
				t.Errorf("struct name %q not found in output", tt.structName)
262
			}
263
		})
264
	}
265
}