4.8 KiB
4.8 KiB
QA procedure: article_title_rules
Package: test (black-box, alongside article_test.go / use_case_baseline_test.go /
not_found_errors_test.go / the hasher-domain-interface tests).
Fakes needed
- Extend
mockArticleRepo(test/article_test.go) / its sharedfailSwitch(test/fakes_common.go) so a configured failure can return a specific error, not only the genericerrRepositoryFailure. TodayfailSwitch.triggeralways returns the same sentinel; add a way to say "the next call toCreatereturnsarticle.ErrInvalidTitle" specifically, distinct from "the next call toCreatereturns a generic repository error" (e.g. afailNextWith(method string, err error)onfailSwitch, keepingerrRepositoryFailureas the default so existing generic-failure tests don't change). - Add a
createCalledflag (or equivalent) tomockArticleRepoif not already present, so a test can assertCreatewas never reached when request-layer validation rejects a title first.
Use-case-level checks (fake repo, no HTTP)
useCases.NewCreateArticleUseCase(repo),CreateArticle(...)with an empty fake repo:- Title
strings.Repeat("😀", 2)(2 runes, 8 bytes) ->errors.Is(err, article.ErrInvalidTitle), nothing stored. - Title
strings.Repeat("😀", 3)(3 runes, 12 bytes) -> no error, created,is_onlinefalse, one article stored. - Title
strings.Repeat("😀", 200)(200 runes, 800 bytes) -> no error, created. Proves the check counts runes (utf8.RuneCountInString), notlen()bytes. - Title
strings.Repeat("😀", 201)(201 runes, 804 bytes) ->errors.Is(err, article.ErrInvalidTitle), nothing stored. - Keep the existing ASCII boundary cases in
TestCreateArticleTitleLengthLimit(0/2/3/200/201) passing unchanged, as a regression check that byte length and rune length coincide for ASCII.
- Title
HTTP checks (real CreateArticleUseCase over the fake repo, mirroring api/router.go)
- Call
validator.InitValidator(). - Build
useCases.NewCreateArticleUseCase(fakeRepo)plusGetArticleUseCase,ListArticlesUseCase,DeleteArticleUseCase(real, over the same fake repo). Buildarticle.NewHandler(create, get, list, delete). Mount its routes inside a group wrapped byjwtauth.Verifier(token)+jwtauth.Authenticator(token)on a freshchi.NewRouter(), with a testjwtauth.New("HS256", []byte("test-secret"), nil), as inapi/router.go. - Mint a valid jwt cookie for user id 1 (
token.Encode(map[string]any{"user_id": uint32(1)}), set as thejwtcookie on eachhttptest.NewRequest). POST /v1/article/with a 2-ASCII-character title ("ab") and a valid body -> status400,fakeRepo.createCalledis false. Assert the body is neitherapperr.ArticleTitleErrorMessagenor"Failed to create article", to keep the two 400 sources (request-layer vs. domain-layer) distinguishable in the test.POST /v1/article/with a 3-ASCII-character title -> status201, response body decodes to the created article JSON,is_onlinefalse.POST /v1/article/with a 200-ASCII-character title (strings.Repeat("a", 200)) -> status201, created.POST /v1/article/with a 201-ASCII-character title -> status400,Createnever called.POST /v1/article/with a title of 200 repetitions of "😀" (200 runes, 800 bytes) and a valid body -> status201, created, response JSON'stitleequals the sent title.- Configure the fake repo (per step 1) so its next
Createcall returnsarticle.ErrInvalidTitledirectly.POST /v1/article/with title "Valid Title" and a valid body (both well inside 3-200 runes, sovalidator.Validate.Structpasses andCreateArticleUseCase's own check would also pass) -> status400, bodyapperr.ArticleTitleErrorMessage + "\n". This scenario is deliberately artificial: with the rule aligned, no real HTTP input can makeCreateArticleUseCase.CreateArticle's own check returnarticle.ErrInvalidTitleoncevalidator.Validate.Structhas already accepted the same title, so the only way to exerciseHandler.PostArticle's mapping branch today is to have the fake repository hand back that sentinel directly, standing in for a future or repository-level source of the same error. - Configure the fake repo to fail on its next
Createwith the genericerrRepositoryFailure(existingfailNext("Create")).POST /v1/article/with title "Valid Title" and a valid body -> status500, body"Failed to create article\n"-- regression proof a non-title failure still answers 500. POST /v1/article/with no jwt cookie -> status401(regression: the route is still gated).
Manual verification (not exercised by the Go test)
- None. This slice has no SPA-visible behaviour and no SMTP involvement.