diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2026-08-18 11:47:38 +0200 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2026-08-18 11:47:38 +0200 |
| commit | 5d17264c8ab8042042162f3b968557aabc4976b3 (patch) | |
| tree | f08c2b2c790077aa79efd749b12c43a12982b608 | |
| parent | 50ba9cfb04e257fafa3fdd566f9f70a1986339e8 (diff) | |
| download | go-gg-5d17264c8ab8042042162f3b968557aabc4976b3.tar.gz | |
test coverage for internal/accept
| -rw-r--r-- | internal/accept/accept.go | 9 | ||||
| -rw-r--r-- | internal/accept/accept_test.go | 81 |
2 files changed, 88 insertions, 2 deletions
diff --git a/internal/accept/accept.go b/internal/accept/accept.go index 5e35f45..5ed6e66 100644 --- a/internal/accept/accept.go +++ b/internal/accept/accept.go @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net> // SPDX-License-Identifier: Apache-2.0 -// TODO: unit test coverage (use the examples from RFC 9110) package accept import ( @@ -50,10 +49,16 @@ func ParseHeader(headers []string) Header { if err != nil { return none } + if _, ok := params["q"]; ok { + // malformed q-value that was not caught by the regex + return none + } opt := option{mediaType, params, 1.0} if weightStr != "" { opt.Weight, err = strconv.ParseFloat(weightStr, 64) if err != nil { + // defense in depth: unreachable because the regex match has + // extremely constrained grammar for `weightStr` return none } if opt.Weight > 1.0 { // this boundary is easier to express here than in the regex @@ -94,7 +99,7 @@ func (h Header) Negotiate(mediaTypes ...string) Option[string] { // we cannot choose from an empty set of options (this can only happen if the // caller gave us no or only malformed media types) - if len(mediaTypes) == 0 { + if len(offers) == 0 { return None[string]() } diff --git a/internal/accept/accept_test.go b/internal/accept/accept_test.go new file mode 100644 index 0000000..90b6934 --- /dev/null +++ b/internal/accept/accept_test.go @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net> +// SPDX-License-Identifier: Apache-2.0 + +package accept_test + +import ( + "testing" + + "go.xyrillian.de/gg/assert" + "go.xyrillian.de/gg/internal/accept" + . "go.xyrillian.de/gg/option" +) + +func TestAcceptWithHeader(t *testing.T) { + h := accept.ParseHeader([]string{"text/*;q=0.3, text/plain;format=flowed, text/plain;format=fixed;q=0.4, */*;q=0.5"}) + + assert.Equal(t, h.Negotiate( + "image/png", // matches with q=0.5 + "text/plain; format=fixed", // matches with q=0.4 + ), Some("image/png")) + + assert.Equal(t, h.Negotiate( + "image/png", // matches with q=0.5 + "text/plain; format=flowed", // matches with q=1.0 + ), Some("text/plain; format=flowed")) + + assert.Equal(t, h.Negotiate( + "text/plain", // matches with q=0.7 + "text/plain; format=flowed", // matches with q=1.0 + ), Some("text/plain; format=flowed")) + + assert.Equal(t, h.Negotiate( + "text/plain", // matches with q=0.7 + "text/plain; format=other", // matches with q=0.3 + ), Some("text/plain")) + + assert.Equal(t, h.Negotiate( + "text/markdown", // matches with q=0.3 + "text/plain", // matches with q=0.3 (but first wins) + ), Some("text/markdown")) +} + +func TestAcceptWithoutHeader(t *testing.T) { + // Negotiate() will always pick the first option + h := accept.ParseHeader(nil) + + assert.Equal(t, h.Negotiate( + "image/png", + "image/jpeg", + ), Some("image/png")) + + assert.Equal(t, h.Negotiate(nil...), None[string]()) + + // malformed media types are ignored + assert.Equal(t, h.Negotiate( + "image/png/foo", + "image/jpeg", + ), Some("image/jpeg")) + + assert.Equal(t, h.Negotiate( + "image/png/foo", + "image/jpeg/foo", + ), None[string]()) +} + +func TestAcceptWithMalformedHeader(t *testing.T) { + for _, brokenHeader := range []string{ + "text/plain, text/markdown/foo", // malformed media type + "text/plain, image/png; q=high", // malformed q-value + "text/plain, image/jpeg; q=1.25", // q-value out of range + } { + h := accept.ParseHeader([]string{brokenHeader}) + + // broken headers are ignored completely, so the first option wins by default + assert.Equal(t, h.Negotiate( + "image/png", + "image/jpeg", + "text/plain", + ), Some("image/png")) + } +} |
