Skip to content

Commit 65d5830

Browse files
authored
fix(go): prevent infinite recursion during json unmarshal of enums (#163)
relates to STACKITSDK-162
1 parent 3817197 commit 65d5830

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

openapi-generator-config-go.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
templateDir: templates/go
2+
files:
3+
custom/model_test.mustache:
4+
# TODO: this should be 'ModelTests' instead of 'Model'
5+
# 'Model' was used because 'ModelTests' didn't stick to golangs file naming conventions
6+
templateType: Model
7+
destinationFilename: _test.go

scripts/generate-sdk/languages/go.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,16 @@ generate_go_sdk() {
153153
--input-spec ${service_json} \
154154
--output ${SERVICES_FOLDER}/${service} \
155155
--package-name ${service} \
156-
--template-dir ${ROOT_DIR}/templates/go/ \
157156
--enable-post-process-file \
158157
--git-host ${GIT_HOST} \
159158
--git-user-id ${GIT_USER_ID} \
160159
--git-repo-id ${GIT_REPO_ID} \
161160
--global-property apis,models,modelTests=true,modelDocs=false,apiDocs=false,supportingFiles \
162161
--additional-properties=isGoSubmodule=true,enumClassPrefix=true,generateInterfaces=true,$regional_api \
163-
--http-user-agent stackit-sdk-go/${service} \
164-
--reserved-words-mappings type=types
162+
--http-user-agent stackit-sdk-go/${service} \
163+
--reserved-words-mappings type=types \
164+
--config openapi-generator-config-go.yml
165+
165166
# Remove unnecessary files
166167
rm ${SERVICES_FOLDER}/${service}/.openapi-generator-ignore
167168
rm ${SERVICES_FOLDER}/${service}/.openapi-generator/FILES
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{{! NOTE: This is a custom STACKIT template which is not present in upsteam to support testing of enum models}}
2+
3+
{{#vars}}
4+
{{! special handling for enums}}
5+
{{#isEnumRef}}
6+
{{#isEnum}}
7+
// isEnum
8+
9+
func Test{{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}_UnmarshalJSON(t *testing.T) {
10+
type args struct {
11+
src []byte
12+
}
13+
tests := []struct {
14+
name string
15+
args args
16+
wantErr bool
17+
}{
18+
{{#allowableValues}}
19+
{{#enumVars}}
20+
{
21+
name: `success - possible enum value no. {{-index}}`,
22+
args: args{
23+
src: []byte(`{{{value}}}`),
24+
},
25+
wantErr: false,
26+
},
27+
{{/enumVars}}
28+
{{/allowableValues}}
29+
{
30+
name: "fail",
31+
args: args{
32+
src: []byte("\"FOOBAR\""),
33+
},
34+
wantErr: true,
35+
},
36+
}
37+
for _, tt := range tests {
38+
t.Run(tt.name, func(t *testing.T) {
39+
v := {{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}({{#isNumeric}}-1{{/isNumeric}}{{^isNumeric}}""{{/isNumeric}})
40+
if err := v.UnmarshalJSON(tt.args.src); (err != nil) != tt.wantErr {
41+
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
42+
}
43+
})
44+
}
45+
}
46+
47+
{{/isEnum}}
48+
{{/isEnumRef}}
49+
{{/vars}}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{#models}}
2+
3+
{{>partial_header}}
4+
package {{packageName}}
5+
6+
import (
7+
"testing"
8+
{{#imports}}
9+
"{{import}}"
10+
{{/imports}}
11+
)
12+
13+
{{#model}}
14+
{{^isEnum}}
15+
{{^oneOf}}{{^anyOf}}
16+
{{>custom/model_simple_test}}
17+
{{/anyOf}}{{/oneOf}}
18+
{{/isEnum}}
19+
{{/model}}
20+
{{/models}}

templates/go/model_simple.mustache

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,13 +305,16 @@ var Allowed{{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titl
305305
}
306306

307307
func (v *{{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}) UnmarshalJSON(src []byte) error {
308-
var value {{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}
308+
// use a type alias to prevent infinite recursion during unmarshal,
309+
// see https://biscuit.ninja/posts/go-avoid-an-infitine-loop-with-custom-json-unmarshallers
310+
type TmpJson {{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}
311+
var value TmpJson
309312
err := json.Unmarshal(src, &value)
310313
if err != nil {
311314
return err
312315
}
313316
// Allow unmarshalling zero value for testing purposes
314-
var zeroValue {{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}
317+
var zeroValue TmpJson
315318
if value == zeroValue {
316319
return nil
317320
}

0 commit comments

Comments
 (0)