package formatter
import (
"io"
"os"
"strings"
"sync"
"testing"
"git.thomasvoss.com/gsp/parser"
)
var (
stdoutMutex sync.Mutex
r *os.File
w *os.File
stdout *os.File
)
func redirectStdout() {
stdoutMutex.Lock()
stdout = os.Stdout
r, w, _ = os.Pipe()
os.Stdout = w
}
func restoreAndCapture() string {
defer stdoutMutex.Unlock()
w.Close()
out, _ := io.ReadAll(r)
os.Stdout = stdout
return string(out)
}
func TestPrintAst(t *testing.T) {
s := `
html lang="en" {
head attr {
title {-
My Website
}
meta .→{} x="y"{}
}
body {
div #some-id {}
div key="val" .class-1 .class-2 {
p {- This is some @em{-emphatic} text }
}
tags key = "Some long value" {}
}
}`
result := `
My Website
This is some emphatic text
`
// Write the source to a temp file
r := strings.NewReader(s)
f, _ := os.CreateTemp("", "tmp*")
defer f.Close()
io.Copy(f, r)
f.Seek(0, 0)
ast, _ := parser.ParseFile(f)
redirectStdout()
PrintAst(ast)
out := restoreAndCapture()
if out != result {
t.Fatalf("PrintAst() printed unexpected string ‘%s’", out)
}
}
func TestPrintAttrsNoClasses(t *testing.T) {
redirectStdout()
printAttrs([]parser.Attr{
{
Key: "foo",
Value: "b&r",
},
{
Key: "baz",
},
{
Key: "hello",
Value: "",
},
{
Key: "class",
Value: "b&z",
},
})
out := restoreAndCapture()
if out != " class=\""foo" <bar> b&z\"" {
t.Fatalf("printAttrs() printed unexpected string ‘%s’", out)
}
}
func TestPrintAttrsMixedAttrs(t *testing.T) {
redirectStdout()
printAttrs([]parser.Attr{
{
Key: "foo",
Value: "bar",
},
{
Key: "baz",
},
{
Key: "class",
Value: "foo",
},
{
Key: "hello",
Value: "world",
},
{
Key: "class",
Value: "bar",
},
{
Key: "class",
Value: "baz",
},
})
out := restoreAndCapture()
if out != " class=\"foo bar baz\" foo=\"bar\" baz hello=\"world\"" {
t.Fatalf("printAttrs() printed unexpected string ‘%s’", out)
}
}
func TestPrintText(t *testing.T) {
redirectStdout()
printText("'Hello' there to you & \"world\"!")
out := restoreAndCapture()
if out != "'Hello' <em>there</em> to you & "world"!" {
t.Fatalf("printText() printed unexpected string ‘%s’", out)
}
}
func TestPrintChildrenTextOnly(t *testing.T) {
redirectStdout()
printChildren([]parser.AstNode{
{
Type: parser.Text,
Text: " \t\x0A Hello ",
},
{
Type: parser.Text,
Text: " There ",
},
{
Type: parser.Text,
Text: " World \x0A\t ",
},
})
out := restoreAndCapture()
if out != " \t\x0A Hello There World \x0A\t " {
t.Fatalf("printChildren() printed unexpected string ‘%s’", out)
}
}
func TestPrintChildrenTrimMixed(t *testing.T) {
redirectStdout()
children := []parser.AstNode{
{
Type: parser.Tagless,
Children: []parser.AstNode{
{
Type: parser.Text,
Text: " Hello World",
},
},
},
}
printChildrenTrim([]parser.AstNode{
{
Type: parser.Normal,
Text: "em",
Children: children,
},
{
Type: parser.Text,
Text: "Foo Bar ",
},
})
out := restoreAndCapture()
if out != " Hello WorldFoo Bar" {
t.Fatalf("printChildrenTrim() printed unexpected string ‘%s’", out)
}
}
func TestPrintChildrenTrimTextOnly(t *testing.T) {
redirectStdout()
printChildrenTrim([]parser.AstNode{
{
Type: parser.Text,
Text: " \t\x0A Hello ",
},
{
Type: parser.Text,
Text: " There ",
},
{
Type: parser.Text,
Text: " World \x0A\t ",
},
})
out := restoreAndCapture()
if out != "Hello There World" {
t.Fatalf("printChildrenTrim() printed unexpected string ‘%s’", out)
}
}
func TestTrimLeftSpaces(t *testing.T) {
sx := " \t \x0AHello World\x0A \t "
sy := "Hello World\x0A \t "
if sz := trimLeftSpaces(sx); sz != sy {
t.Fatalf("trimLeftSpaces() returned ‘%s’", sy)
}
}
func TestTrimRightSpaces(t *testing.T) {
sx := " \t \x0AHello World\x0A \t "
sy := " \t \x0AHello World"
if sz := trimRightSpaces(sx); sz != sy {
t.Fatalf("trimRightSpaces() returned ‘%s’", sy)
}
}
func TestPrintAstWithComments(t *testing.T) {
s := `
html lang="en" {
body {
/ p {= Hello, Sailor!}
p {= Hello, World!}
}
}`
result := `Hello, World!
`
// Write the source to a temp file
r := strings.NewReader(s)
f, _ := os.CreateTemp("", "tmp*")
defer f.Close()
io.Copy(f, r)
f.Seek(0, 0)
ast, _ := parser.ParseFile(f)
redirectStdout()
PrintAst(ast)
out := restoreAndCapture()
if out != result {
t.Fatalf("PrintAst() printed unexpected string ‘%s’", out)
}
}