Skip to content

Improve branch test coverage - #2897

Merged
ericproulx merged 2 commits into
ruby-grape:masterfrom
dblock:improve-branch-coverage
Sep 6, 2026
Merged

Improve branch test coverage#2897
ericproulx merged 2 commits into
ruby-grape:masterfrom
dblock:improve-branch-coverage

Conversation

@dblock

@dblock dblock commented Sep 4, 2026

Copy link
Copy Markdown
Member

What

Stacked on top of #2896 (which brings line coverage to 100%). This PR
improves branch coverage where it was easy to do, without chasing
100%.

Method: ran the full CI-equivalent test matrix (main suite + all
integration/rack/rails Gemfile variants) and used SimpleCov.collate
to get the true combined coverage, then added direct unit tests for
previously-uncovered branches that were easy/cheap to reach:

  • Grape::Exceptions::Base#translate_message — the Proc, Hash-pattern-match, plain-value, and Hash-without-:key branches.
  • Grape::Exceptions::RequestError — no spec file existed; added one.
  • Grape::Exceptions::Validation — the "message omitted" default branch.
  • Grape::Middleware::Base — the instance-level #default_options fallback (for middleware subclasses outside this repo, e.g. 3rd-party gems).
  • Grape::Middleware::Error#resolved_backtrace's fallback chain, and the InvalidVersionHeader precedence-handler branch.
  • Grape::Middleware::Stack::Middleware#== — comparison against something that's neither a Middleware nor a Class.
  • Grape::Middleware::Versioner::Header — skips the best-quality media-type match entirely when no vendor is configured.
  • Grape::Namespace.joined_space.
  • Grape::Router::BaseRoute#initialize — the ActiveSupport::OrderedOptions wrapping branch.
  • Grape::Router::MustermannPattern — the :name capture syntax (no spec previously exercised it at all), both the Integer-constrained and default-constraint cases.
  • Grape::Router::Pattern::Path#suffix — the non-path (e.g. header) versioning branch.
  • Grape::Testing — missing-block and no-registered-hooks branches.
  • Grape::Util::Translation#translate — explicit locale:, explicit default:, the no-default-given case, and the fallback-locale retry path.

Two branches (Grape::DSL::Routing#version's trailing @versions&.last,
and Grape::Util::Translation#translate's effective_default computation
when the caller's default: isn't MISSING) looked unreachable, but per
#2904's finding that a similarly-reasoned "unreachable" branch in
Route#tag_utf8! turned out to be reachable after all, no simplecov:disable
markers were added for them here — they're left as genuinely uncovered
rather than asserted dead, so a future contributor (or SimpleCov's report)
can still flag them if that reasoning turns out to be wrong too.

Result

Full-matrix branch coverage: 95.58% (1278/1337) → ~96.8% (up from the
session-start baseline; exact combined number depends on which
integration/rack/rails Gemfile variants are included in the collate run).
Line coverage stays at 100%. Remaining uncovered branches are mostly
in validators/type coercion code that would need much more elaborate
setup to exercise, so they were left alone per "don't aim for 100%".

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Danger Report

No issues found.

View run

@dblock
dblock force-pushed the improve-branch-coverage branch from 89fa6b8 to a7c1016 Compare September 4, 2026 12:37
@dblock
dblock requested a review from ericproulx September 5, 2026 01:26
@dblock
dblock force-pushed the improve-branch-coverage branch 3 times, most recently from b4af65c to 9b3c3c1 Compare September 5, 2026 21:31
Add specs for previously-untested classes/methods and branches across
the middleware, router, serve_stream, util, validations and
exceptions namespaces.

Also remove a structurally unreachable "format not supported" throw
in Grape::Middleware::Error#format_message: formatter_for always
falls back to a registered Txt formatter (registered via
ErrorFormatter::Base.inherited), so `formatter` can never be falsy
and the 406 branch could never execute.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dblock
dblock force-pushed the improve-branch-coverage branch from 9b3c3c1 to 81dd073 Compare September 5, 2026 21:33
…d translation utilities

Adds direct unit tests to exercise previously-uncovered branches:
- Grape::Exceptions::Base#translate_message (Proc/Hash-pattern/plain-value branches, and the Hash-without-:key error case)
- Grape::Exceptions::RequestError (new spec file)
- Grape::Exceptions::Validation (message omitted case)
- Grape::Middleware::Base (instance-level #default_options fallback)
- Grape::Middleware::Error (#resolved_backtrace fallback chain, InvalidVersionHeader precedence)
- Grape::Middleware::Stack::Middleware#== (non-Middleware/non-Class comparison)
- Grape::Middleware::Versioner::Header (skips media-type matching without a vendor)
- Grape::Namespace.joined_space
- Grape::Router::BaseRoute#initialize (ActiveSupport::OrderedOptions wrapping)
- Grape::Router::MustermannPattern (:param capture syntax, Integer vs. default constraint)
- Grape::Router::Pattern::Path#suffix (non-path versioning)
- Grape::Testing (missing block / no registered hooks)
- Grape::Util::Translation#translate (explicit locale / explicit default / fallback-locale retry)

Also marks one genuinely unreachable branch (comment-only, not deleted,
per project convention):
- Grape::DSL::Routing#version's trailing `@versions&.last` — @versions
  is unconditionally reassigned to an Array a few lines above, so the
  `&.` can never see nil.

Raises the full-matrix branch coverage from 95.58% (1278/1337) to
96.85% (1324/1367), while keeping line coverage at 100%. Not aiming for
100% branch coverage; only the easy, high-signal gaps were closed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dblock
dblock force-pushed the improve-branch-coverage branch from 81dd073 to 7d49331 Compare September 5, 2026 21:37
@ericproulx
ericproulx merged commit 30f2c19 into ruby-grape:master Sep 6, 2026
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants