go/main_test.go

136 lines
3.4 KiB
Go

package main
import (
"bytes"
"github.com/avelino/awesome-go/pkg/markdown"
"os"
"regexp"
"sort"
"strings"
"testing"
"github.com/PuerkitoBio/goquery"
)
var (
reContainsLink = regexp.MustCompile(`\* \[.*\]\(.*\)`)
reOnlyLink = regexp.MustCompile(`\* \[.*\]\([^()]*\)$`)
reLinkWithDescription = regexp.MustCompile(`\* \[.*\]\(.*\) - \S.*[\.\!]`)
)
func requireNoErr(t *testing.T, err error, msg string) {
// FIXME: replace to github.com/stretchr/testify
t.Helper()
if msg == "" {
msg = "unknown error"
}
if err != nil {
t.Fatalf("Received unexpected error [%s]: %+v", msg, err)
}
}
func goqueryFromReadme(t *testing.T) *goquery.Document {
t.Helper()
input, err := os.ReadFile(readmePath)
requireNoErr(t, err, "readme file should be exists")
html, err := markdown.ToHTML(input)
requireNoErr(t, err, "markdown should be rendered to html")
buf := bytes.NewBuffer(html)
doc, err := goquery.NewDocumentFromReader(buf)
requireNoErr(t, err, "html must be valid for goquery")
return doc
}
func TestAlpha(t *testing.T) {
doc := goqueryFromReadme(t)
doc.Find("body > ul").Each(func(i int, s *goquery.Selection) {
if i != 0 {
// skip content menu
// TODO: the sub items (with 3 hash marks `###`) are staying in
// the main list, not respecting the hierarchy and making it
// impossible to test the alphabetical order
testList(t, s)
}
})
}
func TestDuplicatedLinks(t *testing.T) {
doc := goqueryFromReadme(t)
links := make(map[string]bool, 0)
doc.Find("body li > a:first-child").Each(func(_ int, s *goquery.Selection) {
t.Run(s.Text(), func(t *testing.T) {
href, ok := s.Attr("href")
if !ok {
t.Error("expected to have href")
}
if links[href] {
t.Fatalf("duplicated link '%s'", href)
}
links[href] = true
})
})
}
// Test if an entry has description, it must be separated from link with ` - `
func TestSeparator(t *testing.T) {
var matched, containsLink, noDescription bool
input, err := os.ReadFile(readmePath)
requireNoErr(t, err, "readme should be exists")
lines := strings.Split(string(input), "\n")
for _, line := range lines {
line = strings.Trim(line, " ")
containsLink = reContainsLink.MatchString(line)
if containsLink {
noDescription = reOnlyLink.MatchString(line)
if noDescription {
continue
}
matched = reLinkWithDescription.MatchString(line)
if !matched {
t.Errorf("expected entry to be in form of `* [link] - description.`, got '%s'", line)
}
}
}
}
func TestRenderIndex(t *testing.T) {
requireNoErr(t, mkdirAll(outDir), "output dir should exists")
err := renderIndex(readmePath, outIndexFile)
requireNoErr(t, err, "html should be rendered")
}
func testList(t *testing.T, list *goquery.Selection) {
list.Find("ul").Each(func(_ int, items *goquery.Selection) {
testList(t, items)
items.RemoveFiltered("ul")
})
t.Run(list.Prev().Text(), func(t *testing.T) {
checkAlphabeticOrder(t, list)
})
}
func checkAlphabeticOrder(t *testing.T, s *goquery.Selection) {
items := s.Find("li > a:first-child").Map(func(_ int, li *goquery.Selection) string {
return strings.ToLower(li.Text())
})
sorted := make([]string, len(items))
copy(sorted, items)
sort.Strings(sorted)
for k, item := range items {
if item != sorted[k] {
t.Errorf("expected '%s' but actual is '%s'", sorted[k], item)
}
}
if t.Failed() {
t.Logf("expected order is:\n%s", strings.Join(sorted, "\n"))
}
}