package apiutil import ( "testing" "github.com/OffchainLabs/prysm/v7/testing/require" ) func TestParseAccept(t *testing.T) { type want struct { mt string q float64 spec int } cases := []struct { name string header string want []want }{ { name: "empty header becomes */*;q=1", header: "", want: []want{{mt: "*/*", q: 1, spec: 0}}, }, { name: "quality ordering then specificity", header: "application/json;q=0.2, */*;q=0.1, application/xml;q=0.5, text/*;q=0.5", want: []want{ {mt: "application/xml", q: 0.5, spec: 2}, {mt: "text/*", q: 0.5, spec: 1}, {mt: "application/json", q: 0.2, spec: 2}, {mt: "*/*", q: 0.1, spec: 0}, }, }, { name: "invalid pieces are skipped", header: "text/plain; q=boom, application/json", want: []want{{mt: "application/json", q: 1, spec: 2}}, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got := ParseAccept(tc.header) gotProjected := make([]want, len(got)) for i, g := range got { gotProjected[i] = want{mt: g.mt, q: g.q, spec: g.spec} } require.DeepEqual(t, gotProjected, tc.want) }) } } func TestMatches(t *testing.T) { cases := []struct { name string accept string ct string matches bool }{ {"exact match", "application/json", "application/json", true}, {"type wildcard", "application/*;q=0.8", "application/xml", true}, {"global wildcard", "*/*;q=0.1", "image/png", true}, {"explicitly unacceptable (q=0)", "text/*;q=0", "text/plain", false}, {"no match", "image/png", "application/json", false}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got := Matches(tc.accept, tc.ct) require.Equal(t, tc.matches, got) }) } } func TestNegotiate(t *testing.T) { cases := []struct { name string accept string serverTypes []string wantType string ok bool }{ { name: "highest quality wins", accept: "application/json;q=0.8,application/xml;q=0.9", serverTypes: []string{"application/json", "application/xml"}, wantType: "application/xml", ok: true, }, { name: "wildcard matches first server type", accept: "*/*;q=0.5", serverTypes: []string{"application/octet-stream", "application/json"}, wantType: "application/octet-stream", ok: true, }, { name: "no acceptable type", accept: "image/png", serverTypes: []string{"application/json"}, wantType: "", ok: false, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got, ok := Negotiate(tc.accept, tc.serverTypes) require.Equal(t, tc.ok, ok) require.Equal(t, tc.wantType, got) }) } } func TestPrimaryAcceptMatches(t *testing.T) { tests := []struct { name string accept string produced string expect bool }{ { name: "prefers json", accept: "application/json;q=0.9,application/xml", produced: "application/json", expect: true, }, { name: "wildcard application beats other wildcard", accept: "application/*;q=0.2,*/*;q=0.1", produced: "application/xml", expect: true, }, { name: "json wins", accept: "application/xml;q=0.8,application/json;q=0.9", produced: "application/json", expect: true, }, { name: "json loses", accept: "application/xml;q=0.8,application/json;q=0.9,application/octet-stream;q=0.99", produced: "application/json", expect: false, }, { name: "json wins with non q option", accept: "application/xml;q=0.8,image/png,application/json;q=0.9", produced: "application/json", expect: true, }, { name: "json not primary", accept: "image/png,application/json", produced: "application/json", expect: false, }, { name: "absent header", accept: "", produced: "text/plain", expect: true, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := PrimaryAcceptMatches(tc.accept, tc.produced) require.Equal(t, got, tc.expect) }) } }