Codebase list golang-github-pointlander-peg / bbd1a568-b9ab-42f8-b51f-1f64bbd88c61/upstream peg_test.go
bbd1a568-b9ab-42f8-b51f-1f64bbd88c61/upstream

Tree @bbd1a568-b9ab-42f8-b51f-1f64bbd88c61/upstream (Download .tar.gz)

peg_test.go @bbd1a568-b9ab-42f8-b51f-1f64bbd88c61/upstreamraw · history · blame

package main

import (
	"bytes"
	"io/ioutil"
	"os"
	"testing"

	"github.com/pointlander/peg/tree"
)

func TestCorrect(t *testing.T) {
	buffer := `package p
type T Peg {}
Grammar <- !.
`
	p := &Peg{Tree: tree.New(false, false, false), Buffer: buffer}
	p.Init()
	err := p.Parse()
	if err != nil {
		t.Error(err)
	}

	p = &Peg{Tree: tree.New(false, false, false), Buffer: buffer}
	p.Init(Size(1<<15))
	err = p.Parse()
	if err != nil {
		t.Error(err)
	}
}

func TestNoSpacePackage(t *testing.T) {
	buffer := `packagenospace
type T Peg {}
Grammar <- !.
`
	p := &Peg{Tree: tree.New(false, false, false), Buffer: buffer}
	p.Init(Size(1<<15))
	err := p.Parse()
	if err == nil {
		t.Error("packagenospace was parsed without error")
	}
}

func TestNoSpaceType(t *testing.T) {
	buffer := `
package p
typenospace Peg {}
Grammar <- !.
`
	p := &Peg{Tree: tree.New(false, false, false), Buffer: buffer}
	p.Init(Size(1<<15))
	err := p.Parse()
	if err == nil {
		t.Error("typenospace was parsed without error")
	}
}

func TestSame(t *testing.T) {
	buffer, err := ioutil.ReadFile("peg.peg")
	if err != nil {
		t.Error(err)
	}

	p := &Peg{Tree: tree.New(true, true, false), Buffer: string(buffer)}
	p.Init(Size(1<<15))
	if err = p.Parse(); err != nil {
		t.Error(err)
	}

	p.Execute()

	out := &bytes.Buffer{}
	p.Compile("peg.peg.go", []string{"./peg", "-inline", "-switch", "peg.peg"}, out)

	bootstrap, err := ioutil.ReadFile("peg.peg.go")
	if err != nil {
		t.Error(err)
	}

	if len(out.Bytes()) != len(bootstrap) {
		t.Error("code generated from peg.peg is not the same as .go")
		return
	}

	for i, v := range out.Bytes() {
		if v != bootstrap[i] {
			t.Error("code generated from peg.peg is not the same as .go")
			return
		}
	}
}

func TestStrict(t *testing.T) {
	tt := []string{
		// rule used but not defined
		`
package main
type test Peg {}
Begin <- begin !.
`,
		// rule defined but not used
		`
package main
type test Peg {}
Begin <- .
unused <- 'unused'
`,
		// left recursive rule
		`package main
type test Peg {}
Begin <- Begin 'x'
`,
	}

	for i, buffer := range tt {
		p := &Peg{Tree: tree.New(false, false, false), Buffer: buffer}
		p.Init(Size(1<<15))
		if err := p.Parse(); err != nil {
			t.Fatal(err)
		}
		p.Execute()

		f, err := ioutil.TempFile("", "peg")
		if err != nil {
			t.Fatal(err)
		}
		defer func() {
			os.Remove(f.Name())
			f.Close()
		}()
		out := &bytes.Buffer{}
		p.Strict = true
		if err = p.Compile(f.Name(), []string{"peg"}, out); err == nil {
			t.Fatalf("#%d: expected warning error", i)
		}
		p.Strict = false
		if err = p.Compile(f.Name(), []string{"peg"}, out); err != nil {
			t.Fatalf("#%d: unexpected error (%v)", i, err)
		}
	}
}

var files = [...]string{
	"peg.peg",
	"grammars/c/c.peg",
	"grammars/calculator/calculator.peg",
	"grammars/fexl/fexl.peg",
	"grammars/java/java_1_7.peg",
}

func BenchmarkInitOnly(b *testing.B) {
	pegs := []string{}
	for _, file := range files {
		input, err := ioutil.ReadFile(file)
		if err != nil {
			b.Error(err)
		}
		pegs = append(pegs, string(input))
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		for _, peg := range pegs {
			p := &Peg{Tree: tree.New(true, true, false), Buffer: peg}
			p.Init(Size(1<<15))
		}
	}
}

func BenchmarkParse(b *testing.B) {
	pegs := make([]*Peg, len(files))
	for i, file := range files {
		input, err := ioutil.ReadFile(file)
		if err != nil {
			b.Error(err)
		}

		p := &Peg{Tree: tree.New(true, true, false), Buffer: string(input)}
		p.Init(Size(1<<15))
		pegs[i] = p
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		for _, peg := range pegs {
			if err := peg.Parse(); err != nil {
				b.Error(err)
			}
			b.StopTimer()
			peg.Reset()
			b.StartTimer()
		}
	}
}

func BenchmarkResetAndParse(b *testing.B) {
	pegs := make([]*Peg, len(files))
	for i, file := range files {
		input, err := ioutil.ReadFile(file)
		if err != nil {
			b.Error(err)
		}

		p := &Peg{Tree: tree.New(true, true, false), Buffer: string(input)}
		p.Init(Size(1<<15))
		pegs[i] = p
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		for _, peg := range pegs {
			if err := peg.Parse(); err != nil {
				b.Error(err)
			}
			peg.Reset()
		}
	}
}

func BenchmarkInitAndParse(b *testing.B) {
	strs := []string{}
	for _, file := range files {
		input, err := ioutil.ReadFile(file)
		if err != nil {
			b.Error(err)
		}
		strs = append(strs, string(input))
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		for _, str := range strs {
			peg := &Peg{Tree: tree.New(true, true, false), Buffer: str}
			peg.Init(Size(1<<15))
			if err := peg.Parse(); err != nil {
				b.Error(err)
			}
		}
	}
}

func BenchmarkInitResetAndParse(b *testing.B) {
	strs := []string{}
	for _, file := range files {
		input, err := ioutil.ReadFile(file)
		if err != nil {
			b.Error(err)
		}
		strs = append(strs, string(input))
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		for _, str := range strs {
			peg := &Peg{Tree: tree.New(true, true, false), Buffer: str}
			peg.Init(Size(1<<15))
			if err := peg.Parse(); err != nil {
				b.Error(err)
			}
			peg.Reset()
		}
	}
}