cue
cue copied to clipboard
cmd/go: cue get go ignores legitimate JSON map types
What version of CUE are you using (cue version)?
$ cue version v0.9.0-alpha.3
Does this issue reproduce with the latest stable release?
Yes
What did you do?
# Sanity check the tests
exec go run main.go
exec cue get go --local test
cmp main_go_gen.cue main_go_gen.cue-want
-- main_go_gen.cue-want --
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go test
package main
#T1: {
X: [string]: int
Y: int
#T2: {
X: [string]: int
Y: string @go(,S)
}
#S: string
-- go.mod --
module test
-- main.go --
package main
import (
"encoding/json"
"fmt"
"os"
"strconv"
)
type T1 struct {
X map[int]string
Y int
}
type T2 struct {
X map[S]string
Y S
}
type S int
func (s S) MarshalText() ([]byte, error) {
return []byte(fmt.Sprint("p", int(s))), nil
}
func (s *S) UnmarshalText(data []byte) error {
if len(data) == 0 || data[0] != 'p' {
return fmt.Errorf("invalid S value")
}
i, err := strconv.Atoi(string(data[1:]))
if err != nil {
return err
}
*s = S(i)
return nil
}
type T3 struct {
X map[*int]string
Y int
}
var tests = []struct {
in any
wantError string
want string
}{{
in: T1{
X: map[int]string{
123: "foo",
},
Y: 123,
},
want: `{"X":{"123":"foo"},"Y":123}`,
}, {
in: T2{
X: map[S]string{
123: "foo",
},
Y: 123,
},
want: `{"X":{"p123":"foo"},"Y":"p123"}`,
}, {
in: T3{
X: map[*int]string{
new(int): "foo",
},
Y: 123,
},
wantError: `json: unsupported type: map[*int]string`,
}}
func main() {
for i, test := range tests {
fatalf := func(f string, a ...any) {
fmt.Printf("test %d failed: %s\n", i, fmt.Sprintf(f, a...))
os.Exit(1)
}
data, err := json.Marshal(test.in)
if test.wantError != "" {
if err == nil {
fatalf("expected error")
}
if got, want := err.Error(), test.wantError; got != want {
fatalf("unexpected error; got %q want %q", got, want)
}
continue
}
if err != nil {
fatalf("unexpected error: %v", err)
}
if got, want := string(data), test.want; got != want {
fatalf("unexpected result; got %q want %q", got, want)
}
}
}
What did you expect to see?
A passing test.
What did you see instead?
# Sanity check the tests (0.510s)
> exec go run main.go
> exec cue get go --local test
> cmp main_go_gen.cue main_go_gen.cue-want
diff main_go_gen.cue main_go_gen.cue-want
--- main_go_gen.cue
+++ main_go_gen.cue-want
@@ -4,12 +4,13 @@
package main
-#T1: Y: int
+#T1: {
+ X: [string]: int
+ Y: int
#T2: {
+ X: [string]: int
Y: string @go(,S)
}
#S: string
-
-#T3: Y: int
FAIL: /tmp/testscript2542559523/x.txtar/script.txtar:5: main_go_gen.cue and main_go_gen.cue-want differ
The cue get go logic is omitting the X field in two cases where Go's encoding/json generates valid JSON for the types, and it is also generating CUE for the T3 type which can never be marshaled to JSON because the key type is not supported.
At the least, cue get go could generate [string]: ... fields for these maps, but it could probably do better than that when the key is numeric.