all repos

json2go @ c2472d6f39fc78b9f1054066eab3331441856d1b

convert json to go type annotations

json2go/transpiler_test.go (view raw)

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