From 56d3e22afa93d59a13d8409aa55bb815a11d4d98 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Mon, 25 Dec 2023 13:44:35 +0100 Subject: [PATCH] Refactorings, Lint fixes --- .golangci.yml | 12 +-- cache.go | 1 + http.go | 2 +- micropub_test.go | 218 ++++++++++++++++++++++++----------------------- profileImage.go | 2 +- utils.go | 12 +-- utils_test.go | 5 ++ 7 files changed, 130 insertions(+), 122 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 7c0b7a2..d5a5831 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,7 @@ run: timeout: 5m - issue-exit-code: 0 - skip-tests: true + issues-exit-code: 0 + tests: false build-tags: - linux - libsqlite3 @@ -21,7 +21,7 @@ linters: - bidichk - bodyclose - containedctx - - contextcheck + # - contextcheck - dupl - durationcheck - gofmt @@ -32,10 +32,10 @@ linters: - unparam linters-settings: gosimple: - go: "1.19" + go: "1.21" checks: ["all"] - gostatichcheck: - go: "1.19" + staticcheck: + go: "1.21" checks: ["all"] dupl: threshold: 125 \ No newline at end of file diff --git a/cache.go b/cache.go index 2ad7d17..d51a138 100644 --- a/cache.go +++ b/cache.go @@ -171,6 +171,7 @@ func (c *cache) getCache(key string, next http.Handler, r *http.Request) *cacheI } // No cache available // Make and use copy of r + //nolint:contextcheck cr := r.Clone(valueOnlyContext{r.Context()}) // Remove problematic headers cr.Header.Del("If-Modified-Since") diff --git a/http.go b/http.go index 7ca2e4a..499cdb3 100644 --- a/http.go +++ b/http.go @@ -263,7 +263,7 @@ func (a *goBlog) servePostsAliasesRedirects() http.HandlerFunc { } // Check if post or alias path := r.URL.Path - row, err := a.db.QueryRow(` + row, err := a.db.QueryRowContext(r.Context(), ` -- normal posts select 'post', status, visibility, 200 from posts where path = @path union all diff --git a/micropub_test.go b/micropub_test.go index efa3318..d162a3e 100644 --- a/micropub_test.go +++ b/micropub_test.go @@ -15,12 +15,16 @@ import ( "go.hacdias.com/indielib/micropub" ) -func Test_micropubQuery(t *testing.T) { - +func createMicropubTestEnv(t *testing.T) *goBlog { app := &goBlog{ cfg: createDefaultTestConfig(t), } _ = app.initConfig(false) + return app +} + +func Test_micropubQuery(t *testing.T) { + app := createMicropubTestEnv(t) // Create a test post with tags err := app.createPost(&post{ @@ -86,10 +90,7 @@ func Test_micropubQuery(t *testing.T) { } func Test_micropubCreate(t *testing.T) { - app := &goBlog{ - cfg: createDefaultTestConfig(t), - } - _ = app.initConfig(false) + app := createMicropubTestEnv(t) // Modify settings for easier testing bc := app.cfg.Blogs[app.cfg.DefaultBlog] @@ -98,120 +99,127 @@ func Test_micropubCreate(t *testing.T) { handler := addAllScopes(app.getMicropubImplementation().getHandler()) - t.Run("Normal (JSON)", func(t *testing.T) { - postPath := "/create1" - reqBody := `{"type":["h-entry"],"properties":{"content":["Test post"],"mp-slug":["create1"],"category":["Cool"]}}` + t.Run("JSON", func(t *testing.T) { + testCases := []struct { + name, postPath, reqBody string + assertions func(t *testing.T, p *post) + }{ + { + "Normal", + "/create1", + `{"type":["h-entry"],"properties":{"content":["Test post"],"mp-slug":["create1"],"category":["Cool"]}}`, + func(t *testing.T, p *post) { + assert.Equal(t, "Test post", p.Content) + assert.Equal(t, []string{"Cool"}, p.Parameters["tags"]) + }, + }, + { + "Photo", + "/create2", + `{"type":["h-entry"],"properties":{"mp-slug":["create2"],"photo":["https://photos.example.com/123.jpg"]}}`, + func(t *testing.T, p *post) { + assert.Equal(t, "\n![](https://photos.example.com/123.jpg)", p.Content) + assert.Equal(t, []string{"https://photos.example.com/123.jpg"}, p.Parameters["images"]) + }, + }, + { + "Photo with alternative text", + "/create3", + `{"type":["h-entry"],"properties":{"mp-slug":["create3"],"photo":[{ + "value": "https://photos.example.com/123.jpg", + "alt": "This is a photo" + }]}}`, + func(t *testing.T, p *post) { + assert.Equal(t, "\n![This is a photo](https://photos.example.com/123.jpg \"This is a photo\")", p.Content) + assert.Equal(t, []string{"https://photos.example.com/123.jpg"}, p.Parameters["images"]) + assert.Equal(t, []string{"This is a photo"}, p.Parameters["imagealts"]) + }, + }, + } - recorder := httptest.NewRecorder() - req, _ := requests.New().Post().BodyReader(strings.NewReader(reqBody)).ContentType(contenttype.JSONUTF8).Request(context.Background()) - handler.ServeHTTP(recorder, req) + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() - result := recorder.Result() - require.Equal(t, http.StatusAccepted, result.StatusCode) - require.Equal(t, "http://localhost:8080"+postPath, result.Header.Get("Location")) + recorder := httptest.NewRecorder() + req, _ := requests.New().Post().BodyReader(strings.NewReader(tc.reqBody)).ContentType(contenttype.JSONUTF8).Request(context.Background()) + handler.ServeHTTP(recorder, req) - p, err := app.getPost(postPath) - require.NoError(t, err) + result := recorder.Result() + require.Equal(t, http.StatusAccepted, result.StatusCode) + require.Equal(t, "http://localhost:8080"+tc.postPath, result.Header.Get("Location")) + _ = result.Body.Close() - assert.Equal(t, "Test post", p.Content) - assert.Equal(t, []string{"Cool"}, p.Parameters["tags"]) + p, err := app.getPost(tc.postPath) + require.NoError(t, err) + + tc.assertions(t, p) + }) + } }) - t.Run("Photo (JSON)", func(t *testing.T) { - postPath := "/create2" - reqBody := `{"type":["h-entry"],"properties":{"mp-slug":["create2"],"photo":["https://photos.example.com/123.jpg"]}}` + t.Run("Form", func(t *testing.T) { + testCases := []struct { + name, postPath string + bodyForm url.Values + assertions func(t *testing.T, p *post) + }{ + { + "Photo with alternative text", + "/create4", + url.Values{ + "h": []string{"entry"}, + "mp-slug": []string{"create4"}, + "photo": []string{"https://photos.example.com/123.jpg"}, + "mp-photo-alt": []string{"This is a photo"}, + }, + func(t *testing.T, p *post) { + assert.Equal(t, "\n![This is a photo](https://photos.example.com/123.jpg \"This is a photo\")", p.Content) + assert.Equal(t, []string{"https://photos.example.com/123.jpg"}, p.Parameters["images"]) + assert.Equal(t, []string{"This is a photo"}, p.Parameters["imagealts"]) + }, + }, + { + "Custom parameter", + "/create5", + url.Values{ + "h": []string{"entry"}, + "mp-slug": []string{"create5"}, + "random": []string{"Abc", "Def"}, + }, + func(t *testing.T, p *post) { + assert.Equal(t, []string{"Abc", "Def"}, p.Parameters["random"]) + }, + }, + } - recorder := httptest.NewRecorder() - req, _ := requests.New().Post().BodyReader(strings.NewReader(reqBody)).ContentType(contenttype.JSONUTF8).Request(context.Background()) - handler.ServeHTTP(recorder, req) + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() - result := recorder.Result() - require.Equal(t, http.StatusAccepted, result.StatusCode) - require.Equal(t, "http://localhost:8080"+postPath, result.Header.Get("Location")) + recorder := httptest.NewRecorder() + req, _ := requests.New().Post().BodyForm(tc.bodyForm).Request(context.Background()) + handler.ServeHTTP(recorder, req) - p, err := app.getPost(postPath) - require.NoError(t, err) + result := recorder.Result() + require.Equal(t, http.StatusAccepted, result.StatusCode) + require.Equal(t, "http://localhost:8080"+tc.postPath, result.Header.Get("Location")) + _ = result.Body.Close() - assert.Equal(t, "\n![](https://photos.example.com/123.jpg)", p.Content) - assert.Equal(t, []string{"https://photos.example.com/123.jpg"}, p.Parameters["images"]) + p, err := app.getPost(tc.postPath) + require.NoError(t, err) + + tc.assertions(t, p) + }) + } }) - t.Run("Photo with alternative text (JSON)", func(t *testing.T) { - postPath := "/create3" - reqBody := `{"type":["h-entry"],"properties":{"mp-slug":["create3"],"photo":[{ - "value": "https://photos.example.com/123.jpg", - "alt": "This is a photo" - }]}}` - - recorder := httptest.NewRecorder() - req, _ := requests.New().Post().BodyReader(strings.NewReader(reqBody)).ContentType(contenttype.JSONUTF8).Request(context.Background()) - handler.ServeHTTP(recorder, req) - - result := recorder.Result() - require.Equal(t, http.StatusAccepted, result.StatusCode) - require.Equal(t, "http://localhost:8080"+postPath, result.Header.Get("Location")) - - p, err := app.getPost(postPath) - require.NoError(t, err) - - assert.Equal(t, "\n![This is a photo](https://photos.example.com/123.jpg \"This is a photo\")", p.Content) - assert.Equal(t, []string{"https://photos.example.com/123.jpg"}, p.Parameters["images"]) - assert.Equal(t, []string{"This is a photo"}, p.Parameters["imagealts"]) - }) - - t.Run("Photo with alternative text (Form)", func(t *testing.T) { - postPath := "/create4" - - bodyForm := url.Values{} - bodyForm["h"] = []string{"entry"} - bodyForm["mp-slug"] = []string{"create4"} - bodyForm["photo"] = []string{"https://photos.example.com/123.jpg"} - bodyForm["mp-photo-alt"] = []string{"This is a photo"} - - recorder := httptest.NewRecorder() - req, _ := requests.New().Post().BodyForm(bodyForm).Request(context.Background()) - handler.ServeHTTP(recorder, req) - - result := recorder.Result() - require.Equal(t, http.StatusAccepted, result.StatusCode) - require.Equal(t, "http://localhost:8080"+postPath, result.Header.Get("Location")) - - p, err := app.getPost(postPath) - require.NoError(t, err) - - assert.Equal(t, "\n![This is a photo](https://photos.example.com/123.jpg \"This is a photo\")", p.Content) - assert.Equal(t, []string{"https://photos.example.com/123.jpg"}, p.Parameters["images"]) - assert.Equal(t, []string{"This is a photo"}, p.Parameters["imagealts"]) - }) - - t.Run("Custom parameter (Form)", func(t *testing.T) { - postPath := "/create5" - - bodyForm := url.Values{} - bodyForm["h"] = []string{"entry"} - bodyForm["mp-slug"] = []string{"create5"} - bodyForm["random"] = []string{"Abc", "Def"} - - recorder := httptest.NewRecorder() - req, _ := requests.New().Post().BodyForm(bodyForm).Request(context.Background()) - handler.ServeHTTP(recorder, req) - - result := recorder.Result() - require.Equal(t, http.StatusAccepted, result.StatusCode) - require.Equal(t, "http://localhost:8080"+postPath, result.Header.Get("Location")) - - p, err := app.getPost(postPath) - require.NoError(t, err) - - assert.Equal(t, []string{"Abc", "Def"}, p.Parameters["random"]) - }) } func Test_micropubUpdate(t *testing.T) { - app := &goBlog{ - cfg: createDefaultTestConfig(t), - } - _ = app.initConfig(false) + app := createMicropubTestEnv(t) t.Run("Delete", func(t *testing.T) { postPath := "/delete1" diff --git a/profileImage.go b/profileImage.go index 7afacc3..93482e7 100644 --- a/profileImage.go +++ b/profileImage.go @@ -49,7 +49,7 @@ func (a *goBlog) serveProfileImage(format profileImageFormat) http.HandlerFunc { switch format { case profileImageFormatPNG: mediaType = "image/png" - encode = func(output io.Writer, img *image.NRGBA, quality int) error { + encode = func(output io.Writer, img *image.NRGBA, _ int) error { return imaging.Encode(output, img, imaging.PNG, imaging.PNGCompressionLevel(png.BestCompression)) } default: diff --git a/utils.go b/utils.go index e58682b..8216bda 100644 --- a/utils.go +++ b/utils.go @@ -233,11 +233,6 @@ func mBytesString(size int64) string { return fmt.Sprintf("%.2f MB", datasize.ByteSize(size).MBytes()) } -func htmlText(s string) string { - text, _ := htmlTextFromReader(strings.NewReader(s)) - return text -} - // Build policy to only allow a subset of HTML tags var textPolicy = bluemonday.StrictPolicy(). AllowElements("h1", "h2", "h3", "h4", "h5", "h6"). // Headers @@ -411,10 +406,9 @@ func matchTimeDiffLocale(lang string) tdl.Locale { timeDiffLocaleMutex.Lock() defer timeDiffLocaleMutex.Unlock() supportedLangs := []string{"en", "de", "es", "hi", "pt", "ru", "zh-CN"} - var supportedTags []language.Tag - for _, lang := range supportedLangs { - supportedTags = append(supportedTags, language.Make(lang)) - } + supportedTags := lo.Map(supportedLangs, func(lang string, _ int) language.Tag { + return language.Make(lang) + }) matcher := language.NewMatcher(supportedTags) _, idx, _ := matcher.Match(language.Make(lang)) locale := tdl.Locale(supportedLangs[idx]) diff --git a/utils_test.go b/utils_test.go index 62ab440..59b0c40 100644 --- a/utils_test.go +++ b/utils_test.go @@ -88,6 +88,11 @@ func Test_urlHasExt(t *testing.T) { } func Test_htmlText(t *testing.T) { + htmlText := func(s string) string { + text, _ := htmlTextFromReader(strings.NewReader(s)) + return text + } + // Text without HTML assert.Equal(t, "This is a test", htmlText("This is a test")) // Text without HTML and Emojis