| 160 | var spqSeparatorRE = regexp.MustCompile(`(?m:^#.*\n)+`) |
| 161 | |
| 162 | func parseMarkdown(source []byte) (map[string]string, []*Test, error) { |
| 163 | var commandFCB *ast.FencedCodeBlock |
| 164 | var inputs map[string]string |
| 165 | var tests []*Test |
| 166 | doc := goldmark.DefaultParser().Parse(text.NewReader(source)) |
| 167 | err := ast.Walk(doc, func(n ast.Node, entering bool) (ast.WalkStatus, error) { |
| 168 | fcb, ok := n.(*ast.FencedCodeBlock) |
| 169 | if !ok || !entering { |
| 170 | return ast.WalkContinue, nil |
| 171 | } |
| 172 | switch string(fcb.Language(source)) { |
| 173 | case "mdtest-input": |
| 174 | words := fcbInfoWords(fcb, source) |
| 175 | if len(words) < 2 { |
| 176 | return ast.WalkStop, errors.New("mdtest-input without file name") |
| 177 | } |
| 178 | filename := words[1] |
| 179 | if inputs == nil { |
| 180 | inputs = map[string]string{} |
| 181 | } |
| 182 | if _, ok := inputs[filename]; ok { |
| 183 | return ast.WalkStop, errors.New("mdtest-input with duplicate file name") |
| 184 | } |
| 185 | inputs[filename] = fcbLines(fcb, source) |
| 186 | case "mdtest-command": |
| 187 | if commandFCB != nil { |
| 188 | return ast.WalkStop, fcbError(commandFCB, source, "unpaired mdtest-command") |
| 189 | } |
| 190 | commandFCB = fcb |
| 191 | case "mdtest-output": |
| 192 | if commandFCB == nil { |
| 193 | return ast.WalkStop, fcbError(fcb, source, "unpaired mdtest-output") |
| 194 | } |
| 195 | var commandDir string |
| 196 | var commandFails bool |
| 197 | var commandRuntime string |
| 198 | for _, s := range fcbInfoWords(commandFCB, source)[1:] { |
| 199 | switch { |
| 200 | case strings.HasPrefix(s, "dir="): |
| 201 | commandDir = strings.TrimPrefix(s, "dir=") |
| 202 | case s == "fails": |
| 203 | commandFails = true |
| 204 | case s == "runtime=sam": |
| 205 | commandRuntime = "sam" |
| 206 | case s == "runtime=vam": |
| 207 | commandRuntime = "vam" |
| 208 | default: |
| 209 | msg := fmt.Sprintf("unknown word in mdtest-command info string: %q", s) |
| 210 | return ast.WalkStop, fcbError(commandFCB, source, msg) |
| 211 | } |
| 212 | } |
| 213 | expected := fcbLines(fcb, source) |
| 214 | var head bool |
| 215 | if words := fcbInfoWords(fcb, source); len(words) > 1 && words[1] == "head" { |
| 216 | expected = strings.TrimSuffix(expected, "...\n") |
| 217 | head = true |
| 218 | } |
| 219 | tests = append(tests, &Test{ |