1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package usecase_test
4
5import (
6 "testing"
7
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/require"
10
11 "bnema.dev/ermite-actions/workflow"
12 "bnema.dev/ermite/internal/domain"
13 "bnema.dev/ermite/internal/usecase"
14)
15
16func parsePR(t *testing.T, on string) *workflow.Workflow {
17 t.Helper()
18 wf, errs := workflow.Parse("pr.yml", []byte("on:\n"+on+"\njobs:\n j:\n runs-on: x\n steps:\n - run: 'true'\n"))
19 require.Empty(t, errs)
20 return wf
21}
22
23func TestMatchPullRequestTypes(t *testing.T) {
24 def := parsePR(t, " pull_request:\n")
25 for action, want := range map[string]bool{"opened": true, "synchronize": true, "reopened": true, "closed": false} {
26 assert.Equal(t, want, usecase.MatchPullRequest(def, action, "main", nil, false), "default types, "+action)
27 }
28 closed := parsePR(t, " pull_request:\n types: [closed]\n")
29 assert.True(t, usecase.MatchPullRequest(closed, "closed", "main", nil, false))
30 assert.False(t, usecase.MatchPullRequest(closed, "opened", "main", nil, false))
31 both := parsePR(t, " pull_request:\n types: [opened, closed]\n")
32 assert.True(t, usecase.MatchPullRequest(both, "opened", "main", nil, false))
33 assert.True(t, usecase.MatchPullRequest(both, "closed", "main", nil, false))
34 assert.False(t, usecase.MatchPullRequest(both, "synchronize", "main", nil, false))
35 assert.False(t, usecase.MatchPullRequest(parsePR(t, " push:\n"), "opened", "main", nil, false), "no pull_request event")
36 assert.True(t, usecase.MatchPullRequest(parsePR(t, " [push, pull_request]\n"), "opened", "main", nil, false))
37}
38
39func TestMatchPullRequestFilters(t *testing.T) {
40 wf := parsePR(t, " pull_request:\n branches: [main, 'release/**']\n paths: ['src/**', '!src/gen/**']\n")
41 files := func(f ...string) []string { return f }
42 assert.True(t, usecase.MatchPullRequest(wf, "opened", "main", files("src/a.go"), false))
43 assert.True(t, usecase.MatchPullRequest(wf, "opened", "release/1.2", files("README.md", "src/b.go"), false))
44 assert.False(t, usecase.MatchPullRequest(wf, "opened", "dev", files("src/a.go"), false), "the base branch is filtered")
45 assert.False(t, usecase.MatchPullRequest(wf, "opened", "main", files("README.md"), false), "the changed files are filtered")
46 assert.False(t, usecase.MatchPullRequest(wf, "opened", "main", files("src/gen/x.go"), false))
47 assert.True(t, usecase.MatchPullRequest(wf, "opened", "main", nil, true), "an unavailable list passes the paths filter")
48
49 ignore := parsePR(t, " pull_request:\n branches-ignore: [wip]\n paths-ignore: ['docs/**']\n")
50 assert.True(t, usecase.MatchPullRequest(ignore, "synchronize", "main", files("docs/a.md", "x.go"), false))
51 assert.False(t, usecase.MatchPullRequest(ignore, "synchronize", "main", files("docs/a.md"), false))
52 assert.False(t, usecase.MatchPullRequest(ignore, "synchronize", "wip", files("x.go"), false))
53}
54
55func TestPullFilesLink(t *testing.T) {
56 const base = "http://x/pulls/1/files"
57 assert.Empty(t, usecase.PullFilesLink(base, 1, 30, 0))
58 assert.Empty(t, usecase.PullFilesLink(base, 1, 30, 30))
59 assert.Equal(t, `<http://x/pulls/1/files?per_page=30&page=2>; rel="next", <http://x/pulls/1/files?per_page=30&page=3>; rel="last"`, usecase.PullFilesLink(base, 1, 30, 61))
60 assert.Equal(t,
61 `<http://x/pulls/1/files?per_page=30&page=3>; rel="next", <http://x/pulls/1/files?per_page=30&page=3>; rel="last", <http://x/pulls/1/files?per_page=30&page=1>; rel="first", <http://x/pulls/1/files?per_page=30&page=1>; rel="prev"`,
62 usecase.PullFilesLink(base, 2, 30, 61))
63 last := usecase.PullFilesLink(base, 3, 30, 61)
64 assert.NotContains(t, last, "next")
65 assert.Contains(t, last, `page=2>; rel="prev"`)
66 beyond := usecase.PullFilesLink(base, 9, 30, 61)
67 assert.NotContains(t, beyond, "next")
68 assert.Contains(t, beyond, `page=3>; rel="prev"`)
69}
70
71func TestFilePatch(t *testing.T) {
72 f := domain.FileDiff{Hunks: []domain.Hunk{
73 {OldStart: 1, OldLines: 2, NewStart: 1, NewLines: 2, Header: "func x()", Lines: []domain.Line{
74 {Kind: domain.LineContext, Text: "a"}, {Kind: domain.LineDeletion, Text: "b"}, {Kind: domain.LineAddition, Text: "c", NoNewlineAtEOF: true},
75 }},
76 {OldStart: 9, OldLines: 1, NewStart: 9, NewLines: 1, Lines: []domain.Line{{Kind: domain.LineAddition, Text: "z"}}},
77 }}
78 got, ok := usecase.FilePatch(f)
79 require.True(t, ok)
80 assert.Equal(t, "@@ -1,2 +1,2 @@ func x()\n a\n-b\n+c\n\\ No newline at end of file\n@@ -9 +9 @@\n+z", got)
81 _, ok = usecase.FilePatch(domain.FileDiff{Binary: true, Hunks: f.Hunks})
82 assert.False(t, ok, "binary")
83 _, ok = usecase.FilePatch(domain.FileDiff{Truncated: true})
84 assert.False(t, ok, "truncated")
85 _, ok = usecase.FilePatch(domain.FileDiff{Status: domain.FileRenamed})
86 assert.False(t, ok, "a pure rename has no hunk")
87}