Skip to content

Commit 1c77711

Browse files
committed
add tests for update-checks-doc tool
1 parent c8378e0 commit 1c77711

28 files changed

+776
-13
lines changed

scripts/update-checks-doc/main.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
"github.com/rhysd/actionlint"
1616
)
1717

18-
func generatePermalink(src []byte) (string, error) {
18+
func GeneratePermalink(src []byte) (string, error) {
1919
var out bytes.Buffer
2020

2121
b64 := base64.NewEncoder(base64.StdEncoding, &out)
@@ -45,7 +45,7 @@ func generatePermalink(src []byte) (string, error) {
4545
return fmt.Sprintf("[Playground](https://rhysd.github.io/actionlint/#%s)", out.Bytes()), nil
4646
}
4747

48-
func runActionlint(src []byte) ([]byte, error) {
48+
func Actionlint(src []byte) ([]byte, error) {
4949
var out bytes.Buffer
5050

5151
opts := &actionlint.LinterOptions{
@@ -75,7 +75,7 @@ func runActionlint(src []byte) ([]byte, error) {
7575
return b, nil
7676
}
7777

78-
func update(in []byte) ([]byte, error) {
78+
func Update(in []byte) ([]byte, error) {
7979
var buf bytes.Buffer
8080

8181
var input bytes.Buffer
@@ -84,6 +84,7 @@ func update(in []byte) ([]byte, error) {
8484
var inputHeader bool
8585
var outputHeader bool
8686
var inInput bool
87+
var skipOutput bool
8788
var count int
8889
lnum := 0
8990
scan := bufio.NewScanner(bytes.NewReader(in))
@@ -103,6 +104,7 @@ func update(in []byte) ([]byte, error) {
103104
inputHeader = false
104105
outputHeader = false
105106
inInput = false
107+
skipOutput = false
106108
count = 0
107109
}
108110
if strings.HasPrefix(l, `<a name="`) && strings.HasSuffix(l, `"></a>`) {
@@ -138,7 +140,7 @@ func update(in []byte) ([]byte, error) {
138140
return nil, fmt.Errorf("output cannot be generated because example input for %q does not exist", section)
139141
}
140142
log.Printf("Generating output for the input example for %q at line %d", section, lnum)
141-
out, err := runActionlint(input.Bytes())
143+
out, err := Actionlint(input.Bytes())
142144
if err != nil {
143145
return nil, err
144146
}
@@ -152,15 +154,16 @@ func update(in []byte) ([]byte, error) {
152154
if l == "<!-- Skip update output -->" {
153155
log.Printf("Skip updating output for %q due to the comment at line %d", section, lnum)
154156
outputHeader = false
157+
skipOutput = true
155158
}
156159
if strings.HasPrefix(l, "[Playground](https://rhysd.github.io/actionlint/#") && strings.HasSuffix(l, ")") {
157160
if input.Len() == 0 {
158161
return nil, fmt.Errorf("playground link cannot be generated because example input for %q does not exist", section)
159162
}
160-
if !outputHeader {
163+
if !outputHeader && !skipOutput {
161164
return nil, fmt.Errorf("output code block is missing for %q", section)
162165
}
163-
link, err := generatePermalink(input.Bytes())
166+
link, err := GeneratePermalink(input.Bytes())
164167
if err != nil {
165168
return nil, err
166169
}
@@ -175,12 +178,21 @@ func update(in []byte) ([]byte, error) {
175178
if l == "<!-- Skip playground link -->" {
176179
log.Printf("Skip generating playground link for %q due to the comment at line %d", section, lnum)
177180
outputHeader = false
181+
if input.Len() == 0 {
182+
return nil, fmt.Errorf("example input for %q is empty", section)
183+
}
178184
input.Reset()
179185
count++
180186
}
181187
buf.WriteString(l)
182188
buf.WriteByte('\n')
183189
}
190+
if err := scan.Err(); err != nil {
191+
return nil, err
192+
}
193+
if inInput {
194+
return nil, fmt.Errorf("code block for example input for %q is not closed", section)
195+
}
184196
return buf.Bytes(), scan.Err()
185197
}
186198

@@ -202,11 +214,11 @@ func Main(args []string) error {
202214

203215
in, err := os.ReadFile(path)
204216
if err != nil {
205-
return err
217+
return fmt.Errorf("could not read the document file: %w", err)
206218
}
207219
log.Printf("Read %d bytes from %q", len(in), path)
208220

209-
out, err := update(in)
221+
out, err := Update(in)
210222
if err != nil {
211223
return err
212224
}
@@ -221,11 +233,7 @@ func Main(args []string) error {
221233
}
222234

223235
log.Printf("Generate the updated content (%d bytes) for %q", len(out), path)
224-
if err := os.WriteFile(path, out, 0666); err != nil {
225-
return err
226-
}
227-
228-
return nil
236+
return os.WriteFile(path, out, 0666)
229237
}
230238

231239
func main() {
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"runtime"
10+
"strings"
11+
"testing"
12+
13+
"github.com/google/go-cmp/cmp"
14+
)
15+
16+
// Disable trace logs while running tests. Commenting out this function is useful when debugging test cases.
17+
func init() {
18+
log.SetOutput(io.Discard)
19+
}
20+
21+
func must[T any](v T, err error) T {
22+
if err != nil {
23+
panic(err)
24+
}
25+
return v
26+
}
27+
28+
func testErr(t *testing.T, err error, want ...string) {
29+
t.Helper()
30+
if err == nil {
31+
t.Fatal("error did not occur")
32+
}
33+
msg := err.Error()
34+
for _, w := range want {
35+
if !strings.Contains(msg, w) {
36+
t.Errorf("error message %q does not cotnain expected text %q", msg, w)
37+
}
38+
}
39+
}
40+
41+
func TestMainGenerateOK(t *testing.T) {
42+
if runtime.GOOS == "windows" {
43+
t.Skip("update-checks-doc doesn't support Windows")
44+
}
45+
root := t.TempDir()
46+
47+
in := must(os.Open(filepath.FromSlash("testdata/ok/minimal.in")))
48+
path := filepath.FromSlash(root + "/minimal.in")
49+
tmp := must(os.Create(path))
50+
must(io.Copy(tmp, in))
51+
in.Close()
52+
tmp.Close()
53+
54+
if err := Main([]string{"exe", path}); err != nil {
55+
t.Fatal(err)
56+
}
57+
58+
want := must(os.ReadFile(filepath.FromSlash("testdata/ok/minimal.out")))
59+
have := must(os.ReadFile(path))
60+
if !bytes.Equal(want, have) {
61+
t.Fatal(cmp.Diff(want, have))
62+
}
63+
}
64+
65+
func TestMainCheckOK(t *testing.T) {
66+
if runtime.GOOS == "windows" {
67+
t.Skip("update-checks-doc doesn't support Windows")
68+
}
69+
path := filepath.FromSlash("testdata/ok/minimal.out")
70+
if err := Main([]string{"exe", "-check", path}); err != nil {
71+
t.Fatal(err)
72+
}
73+
}
74+
75+
func TestMainCheckError(t *testing.T) {
76+
if runtime.GOOS == "windows" {
77+
t.Skip("update-checks-doc doesn't support Windows")
78+
}
79+
path := filepath.FromSlash("testdata/ok/minimal.in")
80+
testErr(t, Main([]string{"exe", "-check", path}), "checks document has some update")
81+
}
82+
83+
func TestMainFileNotFound(t *testing.T) {
84+
testErr(t, Main([]string{"exe", "-check", "this-file-does-not-exist.md"}), "could not read the document file")
85+
}
86+
87+
func TestMainTooManyArgs(t *testing.T) {
88+
testErr(t, Main([]string{"exe", "a", "b", "c"}), "usage: update-checks-doc [-check] FILE")
89+
}
90+
91+
func TestMainInvalidCheckFlag(t *testing.T) {
92+
testErr(t, Main([]string{"exe", "-c", "foo.md"}), "usage: update-checks-doc [-check] FILE")
93+
}
94+
95+
func TestMainNoUpdate(t *testing.T) {
96+
if runtime.GOOS == "windows" {
97+
t.Skip("update-checks-doc doesn't support Windows")
98+
}
99+
path := filepath.FromSlash("testdata/ok/minimal.out")
100+
if err := Main([]string{"exe", path}); err != nil {
101+
t.Fatal(err)
102+
}
103+
}
104+
105+
func TestMainUpdateError(t *testing.T) {
106+
path := filepath.FromSlash("testdata/err/no_playground_link.md")
107+
if err := Main([]string{"exe", path}); err == nil {
108+
t.Fatal("no error occurred")
109+
}
110+
}
111+
112+
func TestUpdateOK(t *testing.T) {
113+
if runtime.GOOS == "windows" {
114+
t.Skip("update-checks-doc doesn't support Windows")
115+
}
116+
117+
dir := filepath.FromSlash("testdata/ok")
118+
119+
tests := []string{}
120+
for _, e := range must(os.ReadDir(dir)) {
121+
n := e.Name()
122+
if !strings.HasSuffix(n, ".in") {
123+
continue
124+
}
125+
tests = append(tests, strings.TrimSuffix(n, filepath.Ext(n)))
126+
}
127+
128+
for _, tc := range tests {
129+
in := filepath.Join(dir, tc+".in")
130+
out := filepath.Join(dir, tc+".out")
131+
t.Run(tc, func(t *testing.T) {
132+
have, err := Update(must(os.ReadFile(in)))
133+
if err != nil {
134+
t.Fatal(err)
135+
}
136+
want := must(os.ReadFile(out))
137+
if !bytes.Equal(want, have) {
138+
t.Fatal(cmp.Diff(want, have))
139+
}
140+
})
141+
}
142+
}
143+
144+
func TestUpdateError(t *testing.T) {
145+
dir := filepath.FromSlash("testdata/err")
146+
147+
tests := []string{}
148+
for _, e := range must(os.ReadDir(dir)) {
149+
n := e.Name()
150+
if !strings.HasSuffix(n, ".md") {
151+
continue
152+
}
153+
tests = append(tests, strings.TrimSuffix(n, filepath.Ext(n)))
154+
}
155+
156+
for _, tc := range tests {
157+
path := filepath.Join(dir, tc+".md")
158+
t.Run(tc, func(t *testing.T) {
159+
if _, err := Update(must(os.ReadFile(path))); err == nil {
160+
t.Fatal("no error occurred")
161+
}
162+
})
163+
}
164+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<a name="hello"></a>
2+
## Hello
3+
4+
Example input:
5+
6+
```yaml
7+
```
8+
9+
Output:
10+
11+
```
12+
This section will be generated
13+
```
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<a name="hello"></a>
2+
## Hello
3+
4+
Example input:
5+
6+
```yaml
7+
```
8+
9+
Output:
10+
<!-- Skip update output -->
11+
12+
```
13+
This section will NOT be updated
14+
```
15+
16+
[Playground](https://rhysd.github.io/actionlint/#THIS_URL_WILL_BE_UPDATED)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<a name="hello"></a>
2+
## Hello
3+
4+
Example input:
5+
6+
```yaml
7+
```
8+
9+
Output:
10+
<!-- Skip update output -->
11+
12+
```
13+
This section will NOT be updated
14+
```
15+
16+
<!-- Skip playground link -->
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<a name="hello"></a>
2+
## Hello
3+
4+
Example input:
5+
6+
```yaml
7+
```
8+
9+
Output:
10+
11+
```
12+
This section will be updated
13+
```
14+
15+
<!-- Skip playground link -->
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<a name="hello"></a>
2+
## Hello
3+
4+
Output:
5+
6+
```
7+
This section will be generated
8+
```
9+
10+
[Playground](https://rhysd.github.io/actionlint/#THIS_URL_WILL_BE_UPDATED)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<a name="hello"></a>
2+
## Hello
3+
4+
Output:
5+
<!-- Skip update output -->
6+
7+
```
8+
This section will NOT be updated
9+
```
10+
11+
[Playground](https://rhysd.github.io/actionlint/#THIS_URL_WILL_BE_UPDATED)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<a name="hello"></a>
2+
## Hello
3+
4+
Output:
5+
<!-- Skip update output -->
6+
7+
```
8+
This section will NOT be updated
9+
```
10+
11+
<!-- Skip playground link -->
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<a name="hello"></a>
2+
## Hello
3+
4+
Output:
5+
6+
```
7+
This section will be updated
8+
```
9+
10+
<!-- Skip playground link -->

0 commit comments

Comments
 (0)