OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [go/] [printer/] [printer_test.go] - Rev 848

Go to most recent revision | Compare with Previous | Blame | View Log

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package printer

import (
        "bytes"
        "flag"
        "go/ast"
        "go/parser"
        "go/token"
        "io/ioutil"
        "path/filepath"
        "testing"
        "time"
)

const (
        dataDir  = "testdata"
        tabwidth = 8
)

var update = flag.Bool("update", false, "update golden files")

var fset = token.NewFileSet()

func lineString(text []byte, i int) string {
        i0 := i
        for i < len(text) && text[i] != '\n' {
                i++
        }
        return string(text[i0:i])
}

type checkMode uint

const (
        export checkMode = 1 << iota
        rawFormat
)

func runcheck(t *testing.T, source, golden string, mode checkMode) {
        // parse source
        prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
        if err != nil {
                t.Error(err)
                return
        }

        // filter exports if necessary
        if mode&export != 0 {
                ast.FileExports(prog) // ignore result
                prog.Comments = nil   // don't print comments that are not in AST
        }

        // determine printer configuration
        cfg := Config{Tabwidth: tabwidth}
        if mode&rawFormat != 0 {
                cfg.Mode |= RawFormat
        }

        // format source
        var buf bytes.Buffer
        if err := cfg.Fprint(&buf, fset, prog); err != nil {
                t.Error(err)
        }
        res := buf.Bytes()

        // update golden files if necessary
        if *update {
                if err := ioutil.WriteFile(golden, res, 0644); err != nil {
                        t.Error(err)
                }
                return
        }

        // get golden
        gld, err := ioutil.ReadFile(golden)
        if err != nil {
                t.Error(err)
                return
        }

        // compare lengths
        if len(res) != len(gld) {
                t.Errorf("len = %d, expected %d (= len(%s))", len(res), len(gld), golden)
        }

        // compare contents
        for i, line, offs := 0, 1, 0; i < len(res) && i < len(gld); i++ {
                ch := res[i]
                if ch != gld[i] {
                        t.Errorf("%s:%d:%d: %s", source, line, i-offs+1, lineString(res, offs))
                        t.Errorf("%s:%d:%d: %s", golden, line, i-offs+1, lineString(gld, offs))
                        t.Error()
                        return
                }
                if ch == '\n' {
                        line++
                        offs = i + 1
                }
        }
}

func check(t *testing.T, source, golden string, mode checkMode) {
        // start a timer to produce a time-out signal
        tc := make(chan int)
        go func() {
                time.Sleep(10 * time.Second) // plenty of a safety margin, even for very slow machines
                tc <- 0
        }()

        // run the test
        cc := make(chan int)
        go func() {
                runcheck(t, source, golden, mode)
                cc <- 0
        }()

        // wait for the first finisher
        select {
        case <-tc:
                // test running past time out
                t.Errorf("%s: running too slowly", source)
        case <-cc:
                // test finished within alloted time margin
        }
}

type entry struct {
        source, golden string
        mode           checkMode
}

// Use gotest -update to create/update the respective golden files.
var data = []entry{
        {"empty.input", "empty.golden", 0},
        {"comments.input", "comments.golden", 0},
        {"comments.input", "comments.x", export},
        {"linebreaks.input", "linebreaks.golden", 0},
        {"expressions.input", "expressions.golden", 0},
        {"expressions.input", "expressions.raw", rawFormat},
        {"declarations.input", "declarations.golden", 0},
        {"statements.input", "statements.golden", 0},
        {"slow.input", "slow.golden", 0},
}

func TestFiles(t *testing.T) {
        for i, e := range data {
                source := filepath.Join(dataDir, e.source)
                golden := filepath.Join(dataDir, e.golden)
                check(t, source, golden, e.mode)
                // TODO(gri) check that golden is idempotent
                //check(t, golden, golden, e.mode)
                if testing.Short() && i >= 3 {
                        break
                }
        }
}

// TestLineComments, using a simple test case, checks that consequtive line
// comments are properly terminated with a newline even if the AST position
// information is incorrect.
//
func TestLineComments(t *testing.T) {
        const src = `// comment 1
        // comment 2
        // comment 3
        package main
        `

        fset := token.NewFileSet()
        f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
        if err != nil {
                panic(err) // error in test
        }

        var buf bytes.Buffer
        fset = token.NewFileSet() // use the wrong file set
        Fprint(&buf, fset, f)

        nlines := 0
        for _, ch := range buf.Bytes() {
                if ch == '\n' {
                        nlines++
                }
        }

        const expected = 3
        if nlines < expected {
                t.Errorf("got %d, expected %d\n", nlines, expected)
                t.Errorf("result:\n%s", buf.Bytes())
        }
}

// Verify that the printer can be invoked during initialization.
func init() {
        const name = "foobar"
        var buf bytes.Buffer
        if err := Fprint(&buf, fset, &ast.Ident{Name: name}); err != nil {
                panic(err) // error in test
        }
        // in debug mode, the result contains additional information;
        // ignore it
        if s := buf.String(); !debug && s != name {
                panic("got " + s + ", want " + name)
        }
}

// Verify that the printer doesn't crash if the AST contains BadXXX nodes.
func TestBadNodes(t *testing.T) {
        const src = "package p\n("
        const res = "package p\nBadDecl\n"
        f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
        if err == nil {
                t.Error("expected illegal program") // error in test
        }
        var buf bytes.Buffer
        Fprint(&buf, fset, f)
        if buf.String() != res {
                t.Errorf("got %q, expected %q", buf.String(), res)
        }
}

// Print and parse f with 
func testComment(t *testing.T, f *ast.File, srclen int, comment *ast.Comment) {
        f.Comments[0].List[0] = comment
        var buf bytes.Buffer
        for offs := 0; offs <= srclen; offs++ {
                buf.Reset()
                // Printing f should result in a correct program no
                // matter what the (incorrect) comment position is.
                if err := Fprint(&buf, fset, f); err != nil {
                        t.Error(err)
                }
                if _, err := parser.ParseFile(fset, "", buf.Bytes(), 0); err != nil {
                        t.Fatalf("incorrect program for pos = %d:\n%s", comment.Slash, buf.String())
                }
                // Position information is just an offset.
                // Move comment one byte down in the source.
                comment.Slash++
        }
}

// Verify that the printer produces always produces a correct program
// even if the position information of comments introducing newlines
// is incorrect.
func TestBadComments(t *testing.T) {
        const src = `
// first comment - text and position changed by test
package p
import "fmt"
const pi = 3.14 // rough circle
var (
        x, y, z int = 1, 2, 3
        u, v float64
)
func fibo(n int) {
        if n < 2 {
                return n /* seed values */
        }
        return fibo(n-1) + fibo(n-2)
}
`

        f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
        if err != nil {
                t.Error(err) // error in test
        }

        comment := f.Comments[0].List[0]
        pos := comment.Pos()
        if fset.Position(pos).Offset != 1 {
                t.Error("expected offset 1") // error in test
        }

        testComment(t, f, len(src), &ast.Comment{pos, "//-style comment"})
        testComment(t, f, len(src), &ast.Comment{pos, "/*-style comment */"})
        testComment(t, f, len(src), &ast.Comment{pos, "/*-style \n comment */"})
        testComment(t, f, len(src), &ast.Comment{pos, "/*-style comment \n\n\n */"})
}

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.