1package typesafe23import (4 jsonv2 "encoding/json/v2"5 "errors"6 "testing"7)89func TestResponseUnmarshalAndAccessors(t *testing.T) {10 input := []byte(`{"model":"jev-latest","answers":{"a":{"type":"noul","noul":0},"b":{"type":"choice","choice":"yes","confidence":0.5,"probabilities":{"yes":1}},"c":{"type":"score","score":0,"confidence":0,"legend":{"0":"none","1":"yes"},"probabilities":{"0":1,"1":0}},"future":{"type":"future","value":0}},"usage":{"input_tokens":0,"output_tokens":2}}`)11 var response SystemOneResponse12 if err := jsonv2.Unmarshal(input, &response); err != nil {13 t.Fatal(err)14 }15 if got, err := response.Noul("a"); err != nil || got.Noul != 0 {16 t.Fatalf("noul: %#v %v", got, err)17 }18 if got, err := response.Choice("b"); err != nil || got.Choice != "yes" {19 t.Fatalf("choice: %#v %v", got, err)20 }21 if got, err := response.Score("c"); err != nil || got.Score != 0 {22 t.Fatalf("score: %#v %v", got, err)23 }24 var roundtrip map[string]any25 encoded, err := jsonv2.Marshal(response)26 if err != nil {27 t.Fatal(err)28 }29 if err := jsonv2.Unmarshal(encoded, &roundtrip); err != nil {30 t.Fatal(err)31 }32 if _, ok := roundtrip["answers"].(map[string]any)["future"]; !ok {33 t.Fatal("unknown answer was not preserved")34 }35}3637func TestResponseRejectsMissingAndInvalidFields(t *testing.T) {38 cases := []string{39 `{"answers":{},"usage":{"input_tokens":0,"output_tokens":0}}`,40 `{"model":"x","answers":{},"usage":{"input_tokens":0}}`,41 `{"model":"x","answers":{"a":{"type":"noul"}},"usage":{"input_tokens":0,"output_tokens":0}}`,42 `{"model":"x","answers":{"a":{"type":"noul","noul":1.1}},"usage":{"input_tokens":0,"output_tokens":0}}`,43 }44 for _, input := range cases {45 var response SystemOneResponse46 if err := jsonv2.Unmarshal([]byte(input), &response); err == nil {47 t.Fatalf("expected error for %s", input)48 }49 }50}5152func TestResponseRejectsDuplicateAndInvalidUTF8(t *testing.T) {53 duplicate := []byte(`{"model":"x","model":"y","answers":{},"usage":{"input_tokens":0,"output_tokens":0}}`)54 if err := jsonv2.Unmarshal(duplicate, new(SystemOneResponse)); err == nil {55 t.Fatal("duplicate field should be rejected")56 }57 invalidUTF8 := []byte{'{', '"', 'm', 'o', 'd', 'e', 'l', '"', ':', '"', 0xff, '"', ',', '"', 'a', 'n', 's', 'w', 'e', 'r', 's', '"', ':', '{', '}', ',', '"', 'u', 's', 'a', 'g', 'e', '"', ':', '{', '"', 'i', 'n', 'p', 'u', 't', '_', 't', 'o', 'k', 'e', 'n', 's', '"', ':', '0', ',', '"', 'o', 'u', 't', 'p', 'u', 't', '_', 't', 'o', 'k', 'e', 'n', 's', '"', ':', '0', '}', '}'}58 if err := jsonv2.Unmarshal(invalidUTF8, new(SystemOneResponse)); err == nil {59 t.Fatal("invalid UTF-8 should be rejected")60 }61}6263func TestResponseAccessorErrors(t *testing.T) {64 response := SystemOneResponse{Answers: map[string]Answer{"a": ChoiceAnswer{Choice: "x"}}}65 if _, err := response.Noul("missing"); !errors.Is(err, ErrAnswerNotFound) {66 t.Fatalf("missing: %v", err)67 }68 if _, err := response.Noul("a"); !errors.Is(err, ErrAnswerType) {69 t.Fatalf("type: %v", err)70 }71}7273func TestGenericAnswerAccessor(t *testing.T) {74 response := SystemOneResponse{Answers: map[string]Answer{"a": NoulAnswer{Noul: 0}}}75 got, err := response.Answer[NoulAnswer]("a")76 if err != nil || got.Noul != 0 {77 t.Fatalf("got %#v, %v", got, err)78 }79 if _, err := response.Answer[ChoiceAnswer]("a"); !errors.Is(err, ErrAnswerType) {80 t.Fatalf("wrong type: %v", err)81 }82}8384func TestResponseRejectsInvalidProbabilityMaps(t *testing.T) {85 for _, probabilities := range []string{`{}`, `{"yes":null}`} {86 input := `{"model":"x","answers":{"a":{"type":"choice","choice":"yes","confidence":0,"probabilities":` + probabilities + `}},"usage":{"input_tokens":0,"output_tokens":0}}`87 if err := jsonv2.Unmarshal([]byte(input), new(SystemOneResponse)); err == nil {88 t.Fatalf("expected invalid probabilities error for %s", probabilities)89 }90 }91}9293func TestModelListRejectsMalformedCards(t *testing.T) {94 for _, input := range []string{`{"models":[{}]}`, `{"models":[null]}`, `{"models":[{"name":"","description":"x","release_date":"today"}]}`} {95 if err := jsonv2.Unmarshal([]byte(input), new(ListModelsResponse)); err == nil {96 t.Fatalf("expected malformed model error for %s", input)97 }98 }99}