From eb17108b432315d961a4def4c11a82339c6db69d Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Thu, 10 Nov 2022 18:39:48 -0800 Subject: [PATCH] testutil: Add ParseTestCaseFile This moves the logic for parsing a test case file into a separate function named ParseTestCaseFile. This will make it easier for extensions to use the same format for test files, even if they want a different strategy to run them. The function does not do filtering like DoTestCaseFile; that logic has been left inside DoTestCaseFile. Minus that, this function does not modify any logic. The next commits do. --- testutil/testutil.go | 69 +++++++++++++++++++++++++-- testutil/testutil_test.go | 99 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 163 insertions(+), 5 deletions(-) diff --git a/testutil/testutil.go b/testutil/testutil.go index f7cb312..d343639 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -62,8 +62,10 @@ type MarkdownTestCaseOptions struct { Trim bool } -const attributeSeparator = "//- - - - - - - - -//" -const caseSeparator = "//= = = = = = = = = = = = = = = = = = = = = = = =//" +const ( + attributeSeparator = "//- - - - - - - - -//" + caseSeparator = "//= = = = = = = = = = = = = = = = = = = = = = = =//" +) var optionsRegexp *regexp.Regexp = regexp.MustCompile(`(?i)\s*options:(.*)`) @@ -84,8 +86,51 @@ func ParseCliCaseArg() []int { return ret } -// DoTestCaseFile runs test cases in a given file. -func DoTestCaseFile(m goldmark.Markdown, filename string, t TestingT, no ...int) { +// ParseTestCaseFile parses the contents of the given test case file +// and reurns the test cases found inside. +// +// The file should contain zero or more test cases, each in the form: +// +// NUM[:DESC] +// [OPTIONS] +// //- - - - - - - - -// +// INPUT +// //- - - - - - - - -// +// OUTPUT +// //= = = = = = = = = = = = = = = = = = = = = = = =// +// +// Where, +// +// - NUM is a test case number +// - DESC is an optional description +// - OPTIONS, if present, is a JSON object +// - INPUT is the input Markdown +// - OUTPUT holds the expected result from the processor. +// +// Basic example: +// +// 3 +// //- - - - - - - - -// +// Hello, **world**. +// //- - - - - - - - -// +//

Hello, world

+// //= = = = = = = = = = = = = = = = = = = = = = = =// +// +// Example of a description: +// +// 3: supports bold text +// //- - - - - - - - -// +// Hello, **world**. +// [..] +// +// Example of options: +// +// 3: supports bold text +// OPTIONS: {"trim": true} +// //- - - - - - - - -// +// Hello, **world**. +// [..] +func ParseTestCaseFile(filename string) ([]MarkdownTestCase, error) { fp, err := os.Open(filename) if err != nil { panic(err) @@ -158,6 +203,22 @@ func DoTestCaseFile(m goldmark.Markdown, filename string, t TestingT, no ...int) if len(c.Expected) != 0 { c.Expected = c.Expected + "\n" } + + cases = append(cases, c) + } + + return cases, nil +} + +// DoTestCaseFile runs test cases in a given file. +func DoTestCaseFile(m goldmark.Markdown, filename string, t TestingT, no ...int) { + allCases, err := ParseTestCaseFile(filename) + if err != nil { + panic(err) + } + + cases := allCases[:0] + for _, c := range allCases { shouldAdd := len(no) == 0 if !shouldAdd { for _, n := range no { diff --git a/testutil/testutil_test.go b/testutil/testutil_test.go index 2000a00..87e0975 100644 --- a/testutil/testutil_test.go +++ b/testutil/testutil_test.go @@ -1,7 +1,104 @@ package testutil -import "testing" +import ( + "os" + "path/filepath" + "reflect" + "strings" + "testing" +) // This will fail to compile if the TestingT interface is changed in a way // that doesn't conform to testing.T. var _ TestingT = (*testing.T)(nil) + +func TestParseTestCaseFile(t *testing.T) { + tests := []struct { + desc string + give string // contents of the test file + want []MarkdownTestCase + }{ + { + desc: "empty", + give: "", + want: []MarkdownTestCase{}, + }, + { + desc: "simple", + give: strings.Join([]string{ + "1", + "//- - - - - - - - -//", + "input", + "//- - - - - - - - -//", + "output", + "//= = = = = = = = = = = = = = = = = = = = = = = =//", + }, "\n"), + want: []MarkdownTestCase{ + { + No: 1, + Markdown: "input", + Expected: "output\n", + }, + }, + }, + { + desc: "description", + give: strings.Join([]string{ + "2:check something", + "//- - - - - - - - -//", + "hello", + "//- - - - - - - - -//", + "

hello

", + "//= = = = = = = = = = = = = = = = = = = = = = = =//", + }, "\n"), + want: []MarkdownTestCase{ + { + No: 2, + Description: "check something", + Markdown: "hello", + Expected: "

hello

\n", + }, + }, + }, + { + desc: "options", + give: strings.Join([]string{ + "3", + `OPTIONS: {"trim": true}`, + "//- - - - - - - - -//", + "world", + "//- - - - - - - - -//", + "

world

", + "//= = = = = = = = = = = = = = = = = = = = = = = =//", + }, "\n"), + want: []MarkdownTestCase{ + { + No: 3, + Options: MarkdownTestCaseOptions{Trim: true}, + Markdown: "world", + Expected: "

world

\n", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + filename := filepath.Join(t.TempDir(), "give.txt") + if err := os.WriteFile(filename, []byte(tt.give), 0o644); err != nil { + t.Fatal(err) + } + + got, err := ParseTestCaseFile(filename) + if err != nil { + t.Fatalf("could not parse: %v", err) + } + + if !reflect.DeepEqual(tt.want, got) { + t.Errorf("output did not match:") + t.Errorf(" got = %#v", got) + t.Errorf("want = %#v", tt.want) + } + }) + } +}