aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2026-08-18 11:47:38 +0200
committerStefan Majewsky <majewsky@gmx.net>2026-08-18 11:47:38 +0200
commit5d17264c8ab8042042162f3b968557aabc4976b3 (patch)
treef08c2b2c790077aa79efd749b12c43a12982b608
parent50ba9cfb04e257fafa3fdd566f9f70a1986339e8 (diff)
downloadgo-gg-5d17264c8ab8042042162f3b968557aabc4976b3.tar.gz
test coverage for internal/accept
-rw-r--r--internal/accept/accept.go9
-rw-r--r--internal/accept/accept_test.go81
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"))
+ }
+}