package commandkit import ( "bytes" "encoding/json" "reflect" "strings" "testing" "go.yaml.in/yaml/v4" ) type reportJSONValue struct{} func (reportJSONValue) MarshalJSON() ([]byte, error) { return []byte(`{"selected":123456789012345678901234567890,"text":"false"}`), nil } func TestNormalizeReport(t *testing.T) { value := struct { Visible any `json:"visible"` Hidden string `json:"-"` Empty string `json:"empty,omitempty"` }{Visible: reportJSONValue{}, Hidden: "secret"} got, err := normalizeReport(value) if err != nil { t.Fatal(err) } want := map[string]any{"visible": map[string]any{ "selected": json.Number("123456789012345678901234567890"), "text": "false", }} if !reflect.DeepEqual(got, want) { t.Fatalf("got %#v, want %#v", got, want) } if _, err := normalizeReport(make(chan int)); err == nil { t.Fatal("unsupported value should fail") } } func TestYAMLReportValues(t *testing.T) { input := `large: 123456789012345678901234567890 hex: 0xff fraction: .125 text: "false" redacted: "[REDACTED]" zero: 0 no: false nothing: null empty_map: {} empty_list: [] items: [one, "2", null] ` got, err := DecodeYAMLReport(strings.NewReader(input)) if err != nil { t.Fatal(err) } want := map[string]any{ "large": json.Number("123456789012345678901234567890"), "hex": json.Number("255"), "fraction": json.Number("0.125"), "text": "false", "redacted": "[REDACTED]", "zero": json.Number("0"), "no": false, "nothing": nil, "empty_map": map[string]any{}, "empty_list": []any{}, "items": []any{"one", "2", nil}, } if !reflect.DeepEqual(got, want) { t.Fatalf("got %#v, want %#v", got, want) } node, err := reportYAMLNode(got) if err != nil { t.Fatal(err) } data, err := yaml.Marshal(node) if err != nil { t.Fatal(err) } roundtrip, err := DecodeYAMLReport(bytes.NewReader(data)) if err != nil { t.Fatalf("decode %s: %v", data, err) } if !reflect.DeepEqual(roundtrip, want) { t.Fatalf("roundtrip %s: got %#v, want %#v", data, roundtrip, want) } } func TestDecodeYAMLReportRejectsUnsupportedValues(t *testing.T) { for _, input := range []string{"1: value", "a: .inf", "a: !custom value", "a: 1\n---\nb: 2", "a: &a [*a]", "a: 1\na: 2"} { t.Run(input, func(t *testing.T) { if _, err := DecodeYAMLReport(strings.NewReader(input)); err == nil { t.Fatal("expected conversion error") } }) } } func TestYAMLReportLargeNumericScalars(t *testing.T) { for _, tc := range []struct{ input, want string }{ {"1e9999", "1e9999"}, {"0x100000000000000000000", "1208925819614629174706176"}, {"+01.2500e+9999", "1.2500e+9999"}, } { t.Run(tc.input, func(t *testing.T) { got, err := DecodeYAMLReport(strings.NewReader(tc.input)) if err != nil || got != json.Number(tc.want) { t.Fatalf("got %#v, %v; want %s", got, err, tc.want) } }) } for _, input := range []string{`"1e9999"`, `!!str 1e9999`, `.`, `hello`} { got, err := DecodeYAMLReport(strings.NewReader(input)) if err != nil { t.Fatal(err) } if _, ok := got.(string); !ok { t.Fatalf("%q became %#v", input, got) } } } func TestReportYAMLNodePreservesNumericLookingStrings(t *testing.T) { value := map[string]any{"1e9999": "0x100000000000000000000", "number": json.Number("1e9999")} node, err := reportYAMLNode(value) if err != nil { t.Fatal(err) } data, err := yaml.Marshal(node) if err != nil { t.Fatal(err) } got, err := DecodeYAMLReport(bytes.NewReader(data)) if err != nil { t.Fatalf("%s: %v", data, err) } if !reflect.DeepEqual(got, value) { t.Fatalf("%s: got %#v, want %#v", data, got, value) } }