github.com/anthropics/anthropic-sdk-go@v1.70.1/internal/compat/exhaustive_toparam_test.go (about) 1 package compat 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "maps" 7 "reflect" 8 "slices" 9 "testing" 10 11 "github.com/anthropics/anthropic-sdk-go" 12 ) 13 14 // TestToParamExhaustive checks that ToParam keeps all the data of every content 15 // block the API can return. Blocks are synthesized in synthetic_test.go. A 16 // response field with no request counterpart is skipped; when codegen adds one, 17 // convert it in ToParam if a request can carry it, else add it to skipped below. 18 func TestToParamExhaustive(t *testing.T) { 19 skipped := []string{ 20 "CitationCharLocation.file_id", "CitationContentBlockLocation.file_id", "CitationPageLocation.file_id", 21 } 22 betaSkipped := []string{ 23 "BetaCitationCharLocation.file_id", "BetaCitationContentBlockLocation.file_id", "BetaCitationPageLocation.file_id", 24 } 25 for _, tt := range []struct { 26 name string 27 response reflect.Type 28 request reflect.Type 29 skipped []string 30 toParam func([]byte) (any, error) 31 }{ 32 { 33 "content blocks", 34 reflect.TypeFor[anthropic.ContentBlockUnion](), 35 reflect.TypeFor[anthropic.ContentBlockParamUnion](), 36 skipped, 37 func(wire []byte) (any, error) { 38 var block anthropic.ContentBlockUnion 39 if err := json.Unmarshal(wire, &block); err != nil { 40 return nil, err 41 } 42 return block.ToParam(), nil 43 }, 44 }, 45 { 46 "beta content blocks", 47 reflect.TypeFor[anthropic.BetaContentBlockUnion](), 48 reflect.TypeFor[anthropic.BetaContentBlockParamUnion](), 49 betaSkipped, 50 func(wire []byte) (any, error) { 51 var block anthropic.BetaContentBlockUnion 52 if err := json.Unmarshal(wire, &block); err != nil { 53 return nil, err 54 } 55 return block.ToParam(), nil 56 }, 57 }, 58 } { 59 t.Run(tt.name, func(t *testing.T) { 60 synth := newSynthesizer(t, tt.request) 61 for _, v := range unionVariants(tt.response) { 62 for _, s := range synth.responseShapes(v.Type) { 63 t.Run(v.Type.Name()+"/"+s.Name, func(t *testing.T) { 64 wire, err := json.Marshal(s.Value) 65 if err != nil { 66 t.Fatalf("Failed to marshal shape: %v", err) 67 } 68 param, err := tt.toParam(wire) 69 if err != nil { 70 t.Fatalf("Failed to unmarshal %s: %v", wire, err) 71 } 72 want := comparableJSON(t, wire) 73 if got := requestJSON(t, param); !bytes.Equal(got, want) { 74 t.Errorf("ToParam changed the block\n want: %s\n got: %s", want, got) 75 } 76 }) 77 } 78 } 79 got := slices.Collect(maps.Keys(synth.skipped)) 80 if extra := diff(got, tt.skipped); len(extra) > 0 { 81 t.Errorf("new response fields with no request counterpart %q: list them here if no request can carry them", extra) 82 } 83 if stale := diff(tt.skipped, got); len(stale) > 0 { 84 t.Errorf("listed fields no longer skipped %q: remove them", stale) 85 } 86 }) 87 } 88 }