Skip to content

🧹 chore: Expand Binder tests coverage#3714

Merged
ReneWerner87 merged 5 commits intomainfrom
2025-08-26-10-57-52
Aug 28, 2025
Merged

🧹 chore: Expand Binder tests coverage#3714
ReneWerner87 merged 5 commits intomainfrom
2025-08-26-10-57-52

Conversation

@gaby
Copy link
Member

@gaby gaby commented Aug 26, 2025

Summary

  • add error path tests for cookie, header, and resp header binders
  • broaden mapping tests covering decoder builder and edge cases

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 26, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Change refactors per-iteration error handling in multiple Binder.Bind implementations to use inline checks that return immediately on formatBindData errors; adds tests covering parse-error paths, multipart bracket errors, and expanded mapping/decoder behaviors.

Changes

Cohort / File(s) Summary
Binders: early-return on format errors
binder/cookie.go, binder/form.go, binder/header.go, binder/resp_header.go
Replace loop-scoped error accumulation and post-loop checks with inline if err := formatBindData(...); err != nil { return err }. Bind now short-circuits immediately on the first format/formatBindData error; success path still calls parse(...) after the loop. No public signatures changed.
Binder tests: parse-error coverage
binder/cookie_test.go, binder/form_test.go, binder/header_test.go, binder/resp_header_test.go
Add tests asserting Bind returns errors when values cannot be parsed into typed fields (e.g., non-numeric into int) and multipart bracket-related error cases.
Mapping and formatting tests
binder/mapping_test.go
Add tests for decoderBuilder customization, parseToMap with extended types, decoder pool initialization, field-cache behavior and mismatches, equalFieldType checks, field-info building for unexported/nested fields, bracket-notation formatting success, and file-header type mismatch error cases.

Sequence Diagram(s)

sequenceDiagram
  participant Req as Request/Response
  participant Binder as Binder.Bind
  participant FBD as formatBindData
  participant Parse as parse

  Note over Binder: New common flow (cookie/form/header/resp_header)
  Binder->>Req: Iterate fields/headers/cookies
  Binder->>FBD: formatBindData(key, value, data)
  alt formatBindData error
    Binder-->>Req: return error (early)
  else success
    Binder-->>Req: continue
  end
  Binder->>Parse: parse(name, out, data)
  Parse-->>Binder: error or nil
  Binder-->>Req: return
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • sixcolors
  • ReneWerner87
  • efectn

Poem

I twitch my whiskers at each bind and byte,
I hop away when formatData gives a fright.
Cookies and forms now tell me true,
Headers parsed — I skip a few.
I burrow, map, and then I nap. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 533d766 and 4bb78c0.

📒 Files selected for processing (1)
  • binder/header.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • binder/header.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: unit (1.25.x, windows-latest)
  • GitHub Check: repeated
  • GitHub Check: Compare
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 2025-08-26-10-57-52

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@gaby gaby changed the title test: expand binder coverage 🧹 chore: Expand Binder tests coverage Aug 26, 2025
@gaby gaby added the v3 label Aug 26, 2025
@gaby gaby added this to v3 Aug 26, 2025
@codecov
Copy link

codecov bot commented Aug 26, 2025

Codecov Report

❌ Patch coverage is 25.00000% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.05%. Comparing base (3646c82) to head (4bb78c0).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
binder/cookie.go 0.00% 1 Missing and 1 partial ⚠️
binder/header.go 0.00% 1 Missing and 1 partial ⚠️
binder/resp_header.go 0.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3714      +/-   ##
==========================================
+ Coverage   91.77%   92.05%   +0.28%     
==========================================
  Files         115      115              
  Lines       11551    11535      -16     
==========================================
+ Hits        10601    10619      +18     
+ Misses        687      664      -23     
+ Partials      263      252      -11     
Flag Coverage Δ
unittests 92.05% <25.00%> (+0.28%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gaby gaby added this to the v3 milestone Aug 26, 2025
@gaby gaby marked this pull request as ready for review August 26, 2025 14:40
Copilot AI review requested due to automatic review settings August 26, 2025 14:40
@gaby gaby requested a review from a team as a code owner August 26, 2025 14:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR expands test coverage for the Binder module by adding error path tests and broadening mapping tests. The changes focus on testing error scenarios and edge cases that were previously uncovered.

Key changes:

  • Add parse error tests for cookie, header, and response header binders to test error handling when invalid data is provided
  • Extend mapping tests with comprehensive coverage of decoder builder functionality and edge cases
  • Simplify error handling in binder implementations by removing redundant error variable declarations

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
binder/resp_header_test.go Adds parse error test for response header binding
binder/resp_header.go Simplifies error handling by removing redundant error variable
binder/mapping_test.go Adds comprehensive tests for decoder builder, field caching, and edge cases
binder/header_test.go Adds parse error test for header binding
binder/header.go Simplifies error handling and adds errcheck nolint comment
binder/form_test.go Adds parse error tests for form binding including multipart scenarios
binder/form.go Simplifies error handling by removing redundant error variable
binder/cookie_test.go Adds parse error test for cookie binding
binder/cookie.go Simplifies error handling by removing redundant error variable

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (13)
binder/form.go (1)

34-35: Fail-fast on formatBindData error clarifies control flow; verify no partial writes and cross-binder intent

Returning immediately on formatBindData errors improves readability and avoids doing unnecessary work. Two quick follow-ups:

  • Please confirm formatBindData is transactional with respect to the destination map (i.e., it doesn’t partially mutate data before returning an error). If it can, we may end up with partially-bound inputs before parse runs.
  • Header/respHeader binders reportedly ignore formatBindData errors, while form/cookie now short-circuit. If this difference is intentional, consider documenting it in each binder to avoid surprises for users relying on consistent binder semantics.
binder/cookie_test.go (1)

89-100: Strengthen the negative-path test: run in parallel and assert no partial binding

The test correctly exercises the parse error path. Two small improvements:

  • Make the test parallel to match the style used elsewhere and speed up CI.
  • Assert that no partial binding occurred (Age remains zero-value).
 func Test_CookieBinder_Bind_ParseError(t *testing.T) {
-	b := &CookieBinding{}
+	t.Parallel()
+	b := &CookieBinding{}
 	type User struct {
 		Age int `cookie:"age"`
 	}
 	var user User
 	req := fasthttp.AcquireRequest()
 	req.Header.SetCookie("age", "invalid")
 	t.Cleanup(func() { fasthttp.ReleaseRequest(req) })
 	err := b.Bind(req, &user)
 	require.Error(t, err)
+	require.Zero(t, user.Age)
 }
binder/header_test.go (1)

89-100: Make the test parallel and remove case-ambiguity in header name (nitpick)

  • Add t.Parallel for consistency and speed.
  • Optional: set the header using the same casing as the struct tag ("Age") to reduce ambiguity when reading the test (the binder likely treats headers case-insensitively anyway).
 func Test_HeaderBinder_Bind_ParseError(t *testing.T) {
-	b := &HeaderBinding{}
+	t.Parallel()
+	b := &HeaderBinding{}
 	type User struct {
 		Age int `header:"Age"`
 	}
 	var user User
 	req := fasthttp.AcquireRequest()
-	req.Header.Set("age", "invalid")
+	// Use same casing as the tag for clarity (binder is case-insensitive)
+	req.Header.Set("Age", "invalid")
 	t.Cleanup(func() { fasthttp.ReleaseRequest(req) })
 	err := b.Bind(req, &user)
 	require.Error(t, err)
 }
binder/cookie.go (1)

25-26: Early return on formatBindData error is consistent with fail-fast policy; confirm intended divergence from header binder

This change aligns cookie binding with a fail-fast approach (vs. header binder which reportedly ignores formatBindData errors). If this divergence is intentional (e.g., to surface malformed cookie shapes earlier), please document it to set expectations for users switching between binders.

Also, similar to form binder, please confirm formatBindData doesn’t partially mutate data when returning an error.

binder/resp_header_test.go (1)

79-90: Parallelize and assert no partial binding for the negative path

Good coverage of the parse error. Recommend:

  • Add t.Parallel for consistency.
  • Assert that the destination field remains the zero-value when binding fails.
 func Test_RespHeaderBinder_Bind_ParseError(t *testing.T) {
-	b := &RespHeaderBinding{}
+	t.Parallel()
+	b := &RespHeaderBinding{}
 	type User struct {
 		Age int `respHeader:"age"`
 	}
 	var user User
 	resp := fasthttp.AcquireResponse()
 	resp.Header.Set("age", "invalid")
 	t.Cleanup(func() { fasthttp.ReleaseResponse(resp) })
 	err := b.Bind(resp, &user)
 	require.Error(t, err)
+	require.Zero(t, user.Age)
 }
binder/resp_header.go (1)

25-26: Align error-handling with HeaderBinding (formatBindData can't fail here).

Given bracket translation is disabled (last arg = false) and v is a string, formatBindData cannot return an error for response headers. Returning early on a theoretically impossible error makes this binder’s behavior diverge from HeaderBinding, which ignores the error with a clear comment. Consider mirroring HeaderBinding for consistency.

Apply this diff to align behavior:

-		if err := formatBindData(b.Name(), out, data, k, v, b.EnableSplitting, false); err != nil {
-			return err
-		}
+		_ = formatBindData(b.Name(), out, data, k, v, b.EnableSplitting, false) //nolint:errcheck // always returns nil for string values with bracket translation disabled

Optional (perf/readability): switch to the zero-allocation visitor and the narrow helper since headers are strings only:

// Optional: replace the loop with VisitAll + assignBindData
resp.Header.VisitAll(func(key, val []byte) {
	assignBindData(b.Name(), out, data, utils.UnsafeString(key), utils.UnsafeString(val), b.EnableSplitting)
})
binder/header.go (1)

24-24: LGTM; add precondition note or use assignBindData to avoid nolint.

Ignoring formatBindData errors here is correct because: value type is string and bracket translation is disabled. To make this future-proof, consider either:

  • Adding a short precondition comment (value is string; bracket=false ⇒ guaranteed nil), or
  • Using assignBindData, which matches the exact needs and removes the nolint.

Example using assignBindData (optional):

for key, val := range req.Header.All() {
	assignBindData(b.Name(), out, data, utils.UnsafeString(key), utils.UnsafeString(val), b.EnableSplitting)
}

Optional (perf): prefer VisitAll to avoid map allocations, mirroring Fiber’s zero-allocation goals.

binder/form_test.go (3)

57-70: Strengthen the assertion to validate the error content.

The test currently checks only that an error occurs. Verifying the message guards against regressions in error surfacing.

 err := b.Bind(req, &user)
-require.Error(t, err)
+require.Error(t, err)
+require.ErrorContains(t, err, "error converting value for \"age\"")

208-222: Prefer ErrorContains over string Contains on err.Error().

require.ErrorContains reads cleaner and avoids manual .Error() calls.

- require.Error(t, err)
- require.Contains(t, err.Error(), "unmatched brackets")
+ require.Error(t, err)
+ require.ErrorContains(t, err, "unmatched brackets")

223-240: Ditto: use ErrorContains for consistency and clarity.

Same rationale as above.

- require.Error(t, err)
- require.Contains(t, err.Error(), "unmatched brackets")
+ require.Error(t, err)
+ require.ErrorContains(t, err, "unmatched brackets")
binder/mapping_test.go (3)

379-398: Test is a bit weak for map[string]int; assert observable behavior.

The map[string]int branch doesn’t validate outputs. If parseToMap is expected to succeed, asserting the resulting contents avoids a vacuous pass. If values aren’t convertible, clarify the intended fallback (omit keys vs. zero values).

Proposed strengthening:

 m3 := make(map[string]int)
 err = parseToMap(m3, data)
 require.NoError(t, err)
+// If non-convertible values are skipped:
+_, ok := m3["key1"]
+require.False(t, ok)
+// Always present but zeroed if empty input:
+v, ok := m3["empty"]
+require.True(t, ok)
+require.Equal(t, 0, v)

If the intended behavior differs (e.g., attempt conversion and error), please adjust the assertions accordingly to reflect the contract you expect from parseToMap.


400-407: Return decoders to the pool to avoid perturbing later tests.

Not strictly necessary here, but putting the decoder back is cheap and keeps the pool state tidy for subsequent tests.

 for _, tag := range tags {
   decAny := decoderPoolMap[tag].Get()
   dec, ok := decAny.(*schema.Decoder)
   require.True(t, ok)
   require.NotNil(t, dec)
+  decoderPoolMap[tag].Put(dec)
 }

438-454: Unexported-field scenario is covered; verify intention on nestedKinds.

Asserting nestedKinds[reflect.Int] may be brittle if internal representation changes. If the goal is to ensure unexported fields do not break traversal, consider asserting on observed, stable facets (e.g., presence of exported fields under the correct names) rather than internal-kind bookkeeping.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3646c82 and 533d766.

📒 Files selected for processing (9)
  • binder/cookie.go (1 hunks)
  • binder/cookie_test.go (1 hunks)
  • binder/form.go (1 hunks)
  • binder/form_test.go (2 hunks)
  • binder/header.go (1 hunks)
  • binder/header_test.go (1 hunks)
  • binder/mapping_test.go (2 hunks)
  • binder/resp_header.go (1 hunks)
  • binder/resp_header_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:22-25
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The `encryptcookie_test.go` file contains unit tests that validate key lengths for both `EncryptCookie` and `DecryptCookie` functions, ensuring that invalid key lengths raise appropriate errors.

Applied to files:

  • binder/cookie_test.go
📚 Learning: 2024-10-02T23:03:31.727Z
Learnt from: sixcolors
PR: gofiber/fiber#3016
File: middleware/session/store.go:164-167
Timestamp: 2024-10-02T23:03:31.727Z
Learning: Unit tests in this project use testify require.

Applied to files:

  • binder/mapping_test.go
📚 Learning: 2024-12-13T08:14:22.851Z
Learnt from: efectn
PR: gofiber/fiber#3162
File: hooks_test.go:228-228
Timestamp: 2024-12-13T08:14:22.851Z
Learning: In Go test files, prefer using the `require` methods from the `testify` package for assertions instead of manual comparisons and calls to `t.Fatal` or `t.Fatalf`.

Applied to files:

  • binder/mapping_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
PR: gofiber/fiber#2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The project uses the testify/assert package for assertions in unit tests.

Applied to files:

  • binder/mapping_test.go
🧬 Code graph analysis (5)
binder/resp_header_test.go (2)
binder/resp_header.go (2)
  • RespHeaderBinding (9-11)
  • RespHeaderBinding (14-16)
client/response.go (2)
  • AcquireResponse (197-203)
  • ReleaseResponse (207-210)
binder/cookie_test.go (2)
binder/cookie.go (2)
  • CookieBinding (9-11)
  • CookieBinding (14-16)
client/request.go (2)
  • AcquireRequest (950-956)
  • ReleaseRequest (960-963)
binder/header_test.go (1)
binder/header.go (2)
  • HeaderBinding (9-11)
  • HeaderBinding (14-16)
binder/mapping_test.go (2)
binder/mapping.go (2)
  • ParserConfig (19-24)
  • ParserType (28-31)
binder/binder.go (1)
  • ErrMapNotConvertible (11-11)
binder/form_test.go (2)
binder/form.go (2)
  • FormBinding (13-15)
  • FormBinding (18-20)
client/request.go (2)
  • AcquireRequest (950-956)
  • ReleaseRequest (960-963)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: repeated
  • GitHub Check: Compare
🔇 Additional comments (7)
binder/mapping_test.go (7)

7-7: Imports look correct.

strconv and github.com/gofiber/schema are required by the new tests.

Also applies to: 10-10


349-377: Custom converter usage is correct for decoderBuilder.

Good validation of alias tag wiring and custom type conversion. Using a panic inside the converter is consistent with schema’s converter contract (no error return), so keeping the input controlled here is appropriate.


409-419: Field-cache coverage looks good.

Nice sanity checks across known binders plus a panic path for unknown cache keys.


420-425: Map support check is appropriate.

Confirms equalFieldType handles map destinations. Good addition.


426-436: Safe cache-mismatch probe without t.Parallel.

Storing a sentinel into the shared cache can be racy; you’ve intentionally avoided t.Parallel() here, which is the right call. Cleanup via defer cache.Delete(typ) is also good.


455-462: Bracket notation success case is valuable.

Good positive-path complement to the error-path tests. LGTM.


464-471: Type-mismatch error is asserted correctly.

Nice guardrail for file-header handling when the destination map has an incompatible element type.

@gaby
Copy link
Member Author

gaby commented Aug 26, 2025

New coverage

Screenshot_20250826-171903

@ReneWerner87 ReneWerner87 merged commit 82a8485 into main Aug 28, 2025
14 of 15 checks passed
@github-project-automation github-project-automation bot moved this to Done in v3 Aug 28, 2025
@ReneWerner87 ReneWerner87 deleted the 2025-08-26-10-57-52 branch August 28, 2025 07:14
Abhirup-99 pushed a commit to Abhirup-99/fiber that referenced this pull request Nov 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants