Implemented an autocorrect module at the postprocessing stage
This commit is contained in:
190
internal/autocorrect/autocorrect_test.go
Normal file
190
internal/autocorrect/autocorrect_test.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package autocorrect
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadValidRules(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := writeAutocorrect(t, dir, `autocorrect:
|
||||
- target: "Hrank"
|
||||
match:
|
||||
- "Frank"
|
||||
- "frank"
|
||||
`)
|
||||
|
||||
rules, err := Load(path)
|
||||
if err != nil {
|
||||
t.Fatalf("load rules: %v", err)
|
||||
}
|
||||
|
||||
got, count := rules.Apply("Frank and frank")
|
||||
if got != "Hrank and Hrank" {
|
||||
t.Fatalf("text = %q, want %q", got, "Hrank and Hrank")
|
||||
}
|
||||
if count != 2 {
|
||||
t.Fatalf("count = %d, want 2", count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
content string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "missing top-level autocorrect",
|
||||
content: `other: []`,
|
||||
want: "must contain at least one autocorrect rule",
|
||||
},
|
||||
{
|
||||
name: "empty rules list",
|
||||
content: `autocorrect: []`,
|
||||
want: "must contain at least one autocorrect rule",
|
||||
},
|
||||
{
|
||||
name: "empty target",
|
||||
content: `autocorrect:
|
||||
- target: ""
|
||||
match: ["Frank"]
|
||||
`,
|
||||
want: "must include target",
|
||||
},
|
||||
{
|
||||
name: "empty match list",
|
||||
content: `autocorrect:
|
||||
- target: "Hrank"
|
||||
match: []
|
||||
`,
|
||||
want: "must include at least one match string",
|
||||
},
|
||||
{
|
||||
name: "empty match string",
|
||||
content: `autocorrect:
|
||||
- target: "Hrank"
|
||||
match: [" "]
|
||||
`,
|
||||
want: "contains empty match string",
|
||||
},
|
||||
{
|
||||
name: "duplicate match across rules",
|
||||
content: `autocorrect:
|
||||
- target: "Hrank"
|
||||
match: ["Frank"]
|
||||
- target: "Other"
|
||||
match: ["Frank"]
|
||||
`,
|
||||
want: `appears in both rule 0 and rule 1`,
|
||||
},
|
||||
{
|
||||
name: "duplicate match within rule",
|
||||
content: `autocorrect:
|
||||
- target: "Hrank"
|
||||
match: ["Frank", "Frank"]
|
||||
`,
|
||||
want: `contains duplicate match string "Frank"`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := writeAutocorrect(t, dir, test.content)
|
||||
|
||||
_, err := Load(path)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), test.want) {
|
||||
t.Fatalf("expected error to contain %q, got %v", test.want, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyReplacementBehavior(t *testing.T) {
|
||||
rules := Rules{rules: []Rule{
|
||||
{
|
||||
Target: "Hrank",
|
||||
Match: []string{"Frank"},
|
||||
},
|
||||
{
|
||||
Target: "Mike Brown",
|
||||
Match: []string{"Mike Pat"},
|
||||
},
|
||||
{
|
||||
Target: "Godfrey",
|
||||
Match: []string{"God-free"},
|
||||
},
|
||||
}}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
wantCount int
|
||||
}{
|
||||
{
|
||||
name: "case sensitive",
|
||||
input: "Frank and FRANK",
|
||||
want: "Hrank and FRANK",
|
||||
wantCount: 1,
|
||||
},
|
||||
{
|
||||
name: "punctuation boundary",
|
||||
input: "Frank, are you there?",
|
||||
want: "Hrank, are you there?",
|
||||
wantCount: 1,
|
||||
},
|
||||
{
|
||||
name: "no substring in larger token",
|
||||
input: "Franklin and xFrank Frank_y Frank2",
|
||||
want: "Franklin and xFrank Frank_y Frank2",
|
||||
wantCount: 0,
|
||||
},
|
||||
{
|
||||
name: "multi word match",
|
||||
input: "Hello Mike Pat.",
|
||||
want: "Hello Mike Brown.",
|
||||
wantCount: 1,
|
||||
},
|
||||
{
|
||||
name: "hyphenated match",
|
||||
input: "God-free is here.",
|
||||
want: "Godfrey is here.",
|
||||
wantCount: 1,
|
||||
},
|
||||
{
|
||||
name: "hyphen outside match is boundary",
|
||||
input: "x-Frank-y",
|
||||
want: "x-Hrank-y",
|
||||
wantCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
got, count := rules.Apply(test.input)
|
||||
if got != test.want {
|
||||
t.Fatalf("text = %q, want %q", got, test.want)
|
||||
}
|
||||
if count != test.wantCount {
|
||||
t.Fatalf("count = %d, want %d", count, test.wantCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func writeAutocorrect(t *testing.T, dir string, content string) string {
|
||||
t.Helper()
|
||||
|
||||
path := filepath.Join(dir, "autocorrect.yml")
|
||||
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
|
||||
t.Fatalf("write autocorrect file: %v", err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
Reference in New Issue
Block a user