feat: add http-multiple checker for multiple HTTP assertions against same handler#296
Open
mmorel-35 wants to merge 3 commits into
Open
feat: add http-multiple checker for multiple HTTP assertions against same handler#296mmorel-35 wants to merge 3 commits into
mmorel-35 wants to merge 3 commits into
Conversation
…same handler Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
450f5c7 to
196df69
Compare
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
ccoVeille
approved these changes
Mar 14, 2026
Copilot AI
added a commit
to mmorel-35/testifylint
that referenced
this pull request
May 28, 2026
…ssertions against same handler
mmorel-35
pushed a commit
to mmorel-35/testifylint
that referenced
this pull request
May 28, 2026
…ssertions against same handler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Each testify HTTP assertion function (
HTTPStatusCode,HTTPBodyContains, etc.) makes a separate HTTP call to the handler. Multiple assertions with identical(handler, method, url, values)arguments allow a stateful handler to satisfy each test independently — masking bugs that only appear in a real single-request scenario.New checker:
http-multipleDetects when multiple HTTP assertion functions share the same handler and request arguments within a single function scope:
Changes
internal/checkers/http_multiple.go—AdvancedCheckerimplementation: walks each function/closure body (without crossingFuncLitboundaries), groups HTTP assertions by(handler, method, url, values)string key, reports all calls in groups of 2+. Includes a suggested fix that replaces consecutive groups with a scopedhttptestblock.internal/checkers/helpers_import.go— import-addition utilities (identical copy from thehttp-constbranch) providingaddImportFixto resolve a package's local qualifier and optionally insert a missing import as aTextEdit.internal/checkers/checkers_registry.go— registershttp-multiple, enabled by defaultinternal/checkers/checkers_registry_test.go— updates expected checker listsinternal/testgen/gen_http_multiple.go— test generator covering invalid (same args, including*fformatted variants, non-nilurl.Valuesquery params) and valid (single call, different handlers/methods/URLs, cross-closure boundaries) cases; includes aGoldenTemplateshowing the expected state after all fixes are applied; covers non-tTestingT identifiers (e.g.tt)internal/testgen/main.go— registers the generatoranalyzer/checkers_factory_test.go— updates expected advanced checker listsanalyzer/testdata/src/http-multiple-add-import/— separate testdata package (not managed by testgen) exercising the import-addition path end-to-end whennet/http/httptestis not yet presentREADME.md— documents the checker with autofix marked as enabledAutofix
The fix is generated when all calls in a group reside in consecutive top-level statements of the enclosing block and every call is the direct expression of its
ast.ExprStmt(not nested insideif/for/selectbodies). It replaces them with a scoped{ }block:{ req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/path", nil) rr := httptest.NewRecorder() handler(rr, req) assert.Equal(t, http.StatusOK, rr.Code) assert.Contains(t, rr.Body.String(), "hello") }t.Context()is used (wheretis the actual TestingT variable extracted from the original call) so the request context is automatically cancelled when the test ends — without requiring an explicit"context"import. The block wrapper ensures that applying fixes for multiple groups in the same function at once does not produce variable re-declaration errors. The following assertion mappings are used:HTTPStatusCode(..., code)assert.Equal(<t>, code, rr.Code)HTTPBodyContains(..., str)assert.Contains(<t>, rr.Body.String(), str)HTTPBodyNotContains(..., str)assert.NotContains(<t>, rr.Body.String(), str)HTTPError(...)assert.GreaterOrEqual(<t>, rr.Code, 400)HTTPSuccess(...)assert.GreaterOrEqual(<t>, rr.Code, 200)+assert.Less(<t>, rr.Code, 300)HTTPRedirect(...)assert.GreaterOrEqual(<t>, rr.Code, 300)+assert.Less(<t>, rr.Code, 400)Where
<t>is the actual TestingT variable name extracted from each original call (e.g.ttif the test usestt *testing.T).Additional fix safety constraints:
if/for/select/etc. — prevents replacing surrounding control flow.assert.*andrequire.*calls — prevents silent semantic changes.addImportFix(fromhelpers_import.go) to resolve thehttptestqualifier and automatically add thenet/http/httptestimport when not yet present in the file. No"context"import is needed sincet.Context()is used. The fix is offered unconditionally.url.Valuesencoding: whenvaluesis non-nil, the fix emitsreq.URL.RawQuery = <values>.Encode(), mirroring testify's ownhttpCodeimplementation.*fformatted variants are preserved in the replacement. Non-consecutive groups and groups that fail any safety constraint still receive a diagnostic but no fix.Closes #193