• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / modo / 12977073267

26 Jan 2025 06:04PM CUT coverage: 61.986%. Remained the same
12977073267

push

github

web-flow
Fix link labels for aliases (#121)

1 of 1 new or added line in 1 file covered. (100.0%)

1055 of 1702 relevant lines covered (61.99%)

29.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.54
/document/doctest.go
1
package document
2

3
import (
4
        "bufio"
5
        "fmt"
6
        "os"
7
        "path"
8
        "path/filepath"
9
        "strings"
10
)
11

12
const docTestAttr = "doctest"
13
const hideAttr = "hide"
14
const globalAttr = "global"
15

16
func (proc *Processor) extractDocTests() error {
6✔
17
        proc.docTests = []*docTest{}
6✔
18
        return proc.walkDocs(proc.Docs, proc.extractTests, func(elem Named) string {
53✔
19
                return elem.GetFileName()
47✔
20
        })
47✔
21
}
22

23
func (proc *Processor) extractDocTestsMarkdown(baseDir string, build bool) error {
1✔
24
        proc.docTests = []*docTest{}
1✔
25
        outDir := filepath.Clean(proc.Config.OutputDir)
1✔
26
        baseDir = filepath.Clean(baseDir)
1✔
27
        err := filepath.WalkDir(baseDir,
1✔
28
                func(p string, info os.DirEntry, err error) error {
3✔
29
                        if err != nil {
2✔
30
                                return err
×
31
                        }
×
32
                        if info.IsDir() {
3✔
33
                                return nil
1✔
34
                        }
1✔
35
                        return proc.extractMarkdown(p, baseDir, outDir, build)
1✔
36
                })
37
        if err != nil {
1✔
38
                return err
×
39
        }
×
40
        if proc.Config.TestOutput != "" {
2✔
41
                err = proc.writeDocTests(proc.Config.TestOutput)
1✔
42
                if err != nil {
1✔
43
                        return err
×
44
                }
×
45
        }
46
        return nil
1✔
47
}
48

49
func (proc *Processor) extractMarkdown(file, baseDir, outDir string, build bool) error {
1✔
50
        if strings.HasSuffix(strings.ToLower(file), ".json") {
1✔
51
                return nil
×
52
        }
×
53

54
        cleanPath := path.Clean(file)
1✔
55
        relPath := filepath.Clean(strings.TrimPrefix(cleanPath, baseDir))
1✔
56
        targetPath := filepath.Join(outDir, relPath)
1✔
57
        targetDir, _ := filepath.Split(targetPath)
1✔
58

1✔
59
        content, err := os.ReadFile(cleanPath)
1✔
60
        if err != nil {
1✔
61
                return err
×
62
        }
×
63
        contentStr := string(content)
1✔
64
        if strings.HasSuffix(strings.ToLower(file), ".md") {
2✔
65
                var err error
1✔
66
                contentStr, err = proc.extractTests(contentStr, []string{strings.TrimSuffix(relPath, ".md")}, 1)
1✔
67
                if err != nil {
1✔
68
                        return err
×
69
                }
×
70
        }
71

72
        if build {
2✔
73
                err = proc.mkDirs(targetDir)
1✔
74
                if err != nil {
1✔
75
                        return err
×
76
                }
×
77
                return proc.WriteFile(targetPath, contentStr)
1✔
78
        }
79
        return nil
×
80
}
81

82
func (proc *Processor) writeDocTests(dir string) error {
1✔
83
        if dir == "" {
1✔
84
                return nil
×
85
        }
×
86
        for _, test := range proc.docTests {
2✔
87
                b := strings.Builder{}
1✔
88
                err := proc.Template.ExecuteTemplate(&b, "doctest.mojo", test)
1✔
89
                if err != nil {
1✔
90
                        return err
×
91
                }
×
92
                filePath := strings.Join(test.Path, "_")
1✔
93
                filePath += "_" + test.Name + "_test.mojo"
1✔
94
                fullPath := path.Join(dir, filePath)
1✔
95

1✔
96
                parentDir, _ := filepath.Split(filepath.Clean(fullPath))
1✔
97
                err = proc.mkDirs(parentDir)
1✔
98
                if err != nil {
1✔
99
                        return err
×
100
                }
×
101

102
                err = proc.WriteFile(fullPath, b.String())
1✔
103
                if err != nil {
1✔
104
                        return err
×
105
                }
×
106
        }
107
        fmt.Printf("Extracted %d tests.\n", len(proc.docTests))
1✔
108
        return nil
1✔
109
}
110

111
func (proc *Processor) extractTests(text string, elems []string, modElems int) (string, error) {
308✔
112
        t, tests, err := extractTestsText(text, elems, proc.Config.Strict)
308✔
113
        if err != nil {
308✔
114
                return "", err
×
115
        }
×
116
        proc.docTests = append(proc.docTests, tests...)
308✔
117
        return t, nil
308✔
118
}
119

120
func extractTestsText(text string, elems []string, strict bool) (string, []*docTest, error) {
308✔
121
        scanner := bufio.NewScanner(strings.NewReader(text))
308✔
122
        outText := strings.Builder{}
308✔
123

308✔
124
        fenced := false
308✔
125
        blocks := map[string]*docTest{}
308✔
126
        var blockLines []string
308✔
127
        var globalLines []string
308✔
128
        var blockName string
308✔
129
        var excluded bool
308✔
130
        var global bool
308✔
131
        var count int
308✔
132
        for scanner.Scan() {
530✔
133
                origLine := scanner.Text()
222✔
134

222✔
135
                isStart := false
222✔
136
                isFence := strings.HasPrefix(origLine, codeFence3)
222✔
137
                if isFence && !fenced {
237✔
138
                        var ok bool
15✔
139
                        var err error
15✔
140
                        blockName, excluded, global, ok, err = parseBlockAttr(origLine)
15✔
141
                        if err != nil {
15✔
142
                                if err := warnOrError(strict, "%s in %s", err.Error(), strings.Join(elems, ".")); err != nil {
×
143
                                        return "", nil, err
×
144
                                }
×
145
                        }
146
                        if !ok {
15✔
147
                                blockName = ""
×
148
                        }
×
149
                        fenced = true
15✔
150
                        isStart = true
15✔
151
                }
152

153
                if !excluded {
408✔
154
                        outText.WriteString(origLine)
186✔
155
                        outText.WriteRune('\n')
186✔
156
                }
186✔
157

158
                if fenced && !isFence && blockName != "" {
246✔
159
                        if global {
34✔
160
                                globalLines = append(globalLines, origLine)
10✔
161
                        } else {
24✔
162
                                blockLines = append(blockLines, origLine)
14✔
163
                        }
14✔
164
                }
165
                count++
222✔
166

222✔
167
                if isFence && fenced && !isStart {
237✔
168
                        if blockName == "" {
15✔
169
                                excluded = false
×
170
                                global = false
×
171
                                fenced = false
×
172
                                continue
×
173
                        }
174
                        if dt, ok := blocks[blockName]; ok {
24✔
175
                                dt.Code = append(dt.Code, blockLines...)
9✔
176
                                dt.Global = append(dt.Global, globalLines...)
9✔
177
                        } else {
15✔
178
                                blocks[blockName] = &docTest{
6✔
179
                                        Name:   blockName,
6✔
180
                                        Path:   elems,
6✔
181
                                        Code:   append([]string{}, blockLines...),
6✔
182
                                        Global: append([]string{}, globalLines...),
6✔
183
                                }
6✔
184
                        }
6✔
185
                        blockLines = blockLines[:0]
15✔
186
                        globalLines = globalLines[:0]
15✔
187
                        excluded = false
15✔
188
                        global = false
15✔
189
                        fenced = false
15✔
190
                }
191
        }
192
        if err := scanner.Err(); err != nil {
308✔
193
                panic(err)
×
194
        }
195
        if fenced {
308✔
196
                if err := warnOrError(strict, "unbalanced code block in %s", strings.Join(elems, ".")); err != nil {
×
197
                        return "", nil, err
×
198
                }
×
199
        }
200

201
        tests := make([]*docTest, 0, len(blocks))
308✔
202
        for _, block := range blocks {
314✔
203
                tests = append(tests, block)
6✔
204
        }
6✔
205

206
        return strings.TrimSuffix(outText.String(), "\n"), tests, nil
308✔
207
}
208

209
func parseBlockAttr(line string) (name string, hide bool, global bool, ok bool, err error) {
22✔
210
        parts := strings.SplitN(line, "{", 2)
22✔
211
        if len(parts) < 2 {
23✔
212
                return
1✔
213
        }
1✔
214
        attrString := strings.TrimSpace(parts[1])
21✔
215
        if !strings.HasSuffix(attrString, "}") {
21✔
216
                err = fmt.Errorf("missing closing parentheses in code block attributes")
×
217
                return
×
218
        }
×
219
        attrString = strings.TrimSuffix(attrString, "}")
21✔
220

21✔
221
        quoted := false
21✔
222
        attrPairs := strings.FieldsFunc(attrString, func(r rune) bool {
509✔
223
                if r == '"' {
530✔
224
                        quoted = !quoted
42✔
225
                }
42✔
226
                return !quoted && r == ' '
488✔
227
        })
228

229
        for _, pair := range attrPairs {
61✔
230
                elems := strings.Split(pair, "=")
40✔
231
                if len(elems) > 2 {
40✔
232
                        err = fmt.Errorf("malformed code block attributes '%s'", pair)
×
233
                        return
×
234
                }
×
235
                if len(elems) < 2 {
42✔
236
                        continue
2✔
237
                }
238

239
                key := strings.TrimSpace(elems[0])
38✔
240
                if key == docTestAttr {
58✔
241
                        name = strings.Trim(elems[1], "\"")
20✔
242
                        continue
20✔
243
                }
244
                if key == hideAttr {
30✔
245
                        h := strings.Trim(elems[1], "\" ")
12✔
246
                        if h == "true" {
24✔
247
                                hide = true
12✔
248
                        }
12✔
249
                        continue
12✔
250
                }
251
                if key == globalAttr {
11✔
252
                        g := strings.Trim(elems[1], "\"")
5✔
253
                        if g == "true" {
10✔
254
                                global = true
5✔
255
                        }
5✔
256
                        continue
5✔
257
                }
258
        }
259
        ok = true
21✔
260
        return
21✔
261
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc