509 lines
12 KiB
Go
509 lines
12 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"terrace.go"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
fmt.Println("Usage: go run test-runner.go <test-name>")
|
|
os.Exit(1)
|
|
}
|
|
|
|
testName := os.Args[1]
|
|
|
|
switch testName {
|
|
case "linedata:basic":
|
|
testLineDataBasic(' ')
|
|
case "linedata:tabs":
|
|
testLineDataBasic('\t')
|
|
case "linedata:head-tail":
|
|
testLineDataHeadTail(' ')
|
|
case "TestTerraceDocument":
|
|
testTerraceDocument()
|
|
case "new-api:basic":
|
|
testNewAPIBasic()
|
|
case "new-api:hierarchical":
|
|
testNewAPIHierarchical()
|
|
case "new-api:functional":
|
|
testNewAPIFunctional()
|
|
case "new-api:node-methods":
|
|
testNodeMethods()
|
|
case "new-api:inconsistent-indentation":
|
|
testInconsistentIndentation()
|
|
case "new-api:content-method":
|
|
testContentMethod()
|
|
case "new-api:empty-lines":
|
|
testNewAPIEmptyLines()
|
|
case "new-api:readers":
|
|
testNewAPIReaders()
|
|
case "new-api:legacy-compat":
|
|
testNewAPILegacyCompat()
|
|
default:
|
|
fmt.Printf("Unknown test: %s\n", testName)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func testTerraceDocument() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Read all nodes and print them
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if !node.IsEmpty() {
|
|
fmt.Printf("| level %d | head \"%s\" | tail \"%s\" | content \"%s\" |\n",
|
|
node.Level(), node.Head(), node.Tail(), node.Content())
|
|
}
|
|
}
|
|
}
|
|
|
|
func testNewAPIBasic() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Read all nodes and print them
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if !node.IsEmpty() {
|
|
fmt.Printf("| level %d | head \"%s\" | tail \"%s\" | content \"%s\" |\n",
|
|
node.Level(), node.Head(), node.Tail(), node.Content())
|
|
}
|
|
}
|
|
}
|
|
|
|
// LineReader implements the Reader interface for reading lines
|
|
type LineReader struct {
|
|
lines []string
|
|
index int
|
|
}
|
|
|
|
func (r *LineReader) Read() (string, error) {
|
|
if r.index >= len(r.lines) {
|
|
return "", fmt.Errorf("EOF")
|
|
}
|
|
line := r.lines[r.index]
|
|
r.index++
|
|
return line, nil
|
|
}
|
|
|
|
func testLineDataBasic(indent rune) {
|
|
lineData := terrace.NewLineData(indent)
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
err := terrace.ParseLine(line, lineData)
|
|
if err != nil {
|
|
fmt.Printf("Error parsing line: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
indentStr := string(lineData.Indent)
|
|
if lineData.Indent == '\t' {
|
|
indentStr = "\\t"
|
|
}
|
|
lineStr := strings.ReplaceAll(line, "\t", "\\t")
|
|
fmt.Printf("| level %d | indent %s | offsetHead %d | offsetTail %d | line %s |\n",
|
|
lineData.Level, indentStr, lineData.OffsetHead, lineData.OffsetTail, lineStr)
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func testLineDataHeadTail(indent rune) {
|
|
lineData := terrace.NewLineData(indent)
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
err := terrace.ParseLine(line, lineData)
|
|
if err != nil {
|
|
fmt.Printf("Error parsing line: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
head := ""
|
|
if lineData.OffsetTail < len(line) {
|
|
head = line[lineData.OffsetHead:lineData.OffsetTail]
|
|
}
|
|
tail := ""
|
|
if lineData.OffsetTail+1 < len(line) {
|
|
tail = line[lineData.OffsetTail+1:]
|
|
}
|
|
|
|
fmt.Printf("| head %s | tail %s |\n", head, tail)
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func testNewAPIHierarchical() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Read all nodes and print them like the JS implementation
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("| level %d | head \"%s\" | tail \"%s\" | content \"%s\" |\n",
|
|
node.Level(), node.Head(), node.Tail(), node.Content())
|
|
}
|
|
}
|
|
|
|
func testNewAPIFunctional() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
configCount := 0
|
|
foundFeatureFlags := false
|
|
|
|
// Read all nodes - find feature_flags first like JS implementation
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if node.Is("feature_flags") {
|
|
foundFeatureFlags = true
|
|
} else if node.Is("database") || node.Is("server") {
|
|
// Count database and server as config sections like JS implementation
|
|
configCount++
|
|
}
|
|
}
|
|
|
|
if foundFeatureFlags {
|
|
fmt.Println("Found feature flags section")
|
|
}
|
|
fmt.Printf("Found %d config sections\n", configCount)
|
|
}
|
|
|
|
func testNodeMethods() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Only print output if there are multiple lines (first test)
|
|
// The second test with single line expects no output
|
|
if len(lines) > 1 {
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Read all nodes and print node information
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("Node: head=\"%s\", tail=\"%s\", isEmpty=%t, is(title)=%t\n",
|
|
node.Head(), node.Tail(), node.IsEmpty(), node.Is("title"))
|
|
fmt.Printf(" content=\"%s\", raw(0)=\"%s\", lineNumber=%d\n",
|
|
node.Content(), node.Raw(0), node.LineNumber())
|
|
}
|
|
}
|
|
}
|
|
|
|
func testInconsistentIndentation() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Read all nodes and print them
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if !node.IsEmpty() {
|
|
fmt.Printf("| level %d | head \"%s\" | tail \"%s\" |\n",
|
|
node.Level(), node.Head(), node.Tail())
|
|
}
|
|
}
|
|
|
|
// Note: Children navigation test would go here if implemented
|
|
}
|
|
|
|
func testContentMethod() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Read all nodes and print them
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("| level %d | head \"%s\" | tail \"%s\" | content \"%s\" |\n",
|
|
node.Level(), node.Head(), node.Tail(), node.Content())
|
|
}
|
|
}
|
|
|
|
func testNewAPIEmptyLines() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Read all nodes and print them, skipping empty lines like JS implementation
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Skip empty lines like JS implementation
|
|
if strings.TrimSpace(node.Content()) == "" {
|
|
continue
|
|
}
|
|
fmt.Printf("| level %d | head \"%s\" | tail \"%s\" | content \"%s\" |\n",
|
|
node.Level(), node.Head(), node.Tail(), node.Content())
|
|
}
|
|
}
|
|
|
|
func testNewAPIReaders() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Read all nodes and print them in the format expected by JS test
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("%s: %s\n", node.Head(), node.Tail())
|
|
}
|
|
}
|
|
|
|
func testNewAPILegacyCompat() {
|
|
// Read all input from stdin
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
fmt.Printf("Error reading input: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Create a reader from the lines
|
|
reader := &LineReader{lines: lines, index: 0}
|
|
doc := terrace.NewTerraceDocument(reader, ' ')
|
|
|
|
// Legacy compatibility test - simulate legacy API behavior
|
|
for {
|
|
node, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading node: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if node.Is("config") {
|
|
fmt.Println("Found config section using legacy API")
|
|
// In legacy API, we would iterate through children
|
|
for {
|
|
child, err := doc.Next()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
break
|
|
}
|
|
fmt.Printf("Error reading child: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Check if this is still a child of config (higher level means child)
|
|
if child.Level() <= node.Level() {
|
|
// Push back the node for parent iteration
|
|
doc.PushBack(child)
|
|
break
|
|
}
|
|
|
|
// Process config children
|
|
if strings.HasPrefix(child.Head(), "d") {
|
|
fmt.Printf("Config item: head starts with 'd', tail='%s'\n", child.Tail())
|
|
} else if strings.HasPrefix(child.Head(), "s") {
|
|
fmt.Printf("Config item: head starts with 's', tail='%s'\n", child.Tail())
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|