~ubuntu-branches/ubuntu/utopic/golang/utopic

« back to all changes in this revision

Viewing changes to src/pkg/go/printer/printer_test.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
 
7
7
import (
8
8
        "bytes"
 
9
        "errors"
9
10
        "flag"
 
11
        "fmt"
10
12
        "go/ast"
11
13
        "go/parser"
12
14
        "go/token"
25
27
 
26
28
var fset = token.NewFileSet()
27
29
 
28
 
func lineString(text []byte, i int) string {
29
 
        i0 := i
30
 
        for i < len(text) && text[i] != '\n' {
31
 
                i++
32
 
        }
33
 
        return string(text[i0:i])
34
 
}
35
 
 
36
30
type checkMode uint
37
31
 
38
32
const (
39
33
        export checkMode = 1 << iota
40
34
        rawFormat
 
35
        idempotent
41
36
)
42
37
 
43
 
func runcheck(t *testing.T, source, golden string, mode checkMode) {
44
 
        // parse source
45
 
        prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
 
38
// format parses src, prints the corresponding AST, verifies the resulting
 
39
// src is syntactically correct, and returns the resulting src or an error
 
40
// if any.
 
41
func format(src []byte, mode checkMode) ([]byte, error) {
 
42
        // parse src
 
43
        f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
46
44
        if err != nil {
47
 
                t.Error(err)
48
 
                return
 
45
                return nil, fmt.Errorf("parse: %s\n%s", err, src)
49
46
        }
50
47
 
51
48
        // filter exports if necessary
52
49
        if mode&export != 0 {
53
 
                ast.FileExports(prog) // ignore result
54
 
                prog.Comments = nil   // don't print comments that are not in AST
 
50
                ast.FileExports(f) // ignore result
 
51
                f.Comments = nil   // don't print comments that are not in AST
55
52
        }
56
53
 
57
54
        // determine printer configuration
60
57
                cfg.Mode |= RawFormat
61
58
        }
62
59
 
63
 
        // format source
 
60
        // print AST
64
61
        var buf bytes.Buffer
65
 
        if err := cfg.Fprint(&buf, fset, prog); err != nil {
66
 
                t.Error(err)
 
62
        if err := cfg.Fprint(&buf, fset, f); err != nil {
 
63
                return nil, fmt.Errorf("print: %s", err)
67
64
        }
 
65
 
 
66
        // make sure formated output is syntactically correct
68
67
        res := buf.Bytes()
69
 
 
70
 
        // formatted source must be valid
71
68
        if _, err := parser.ParseFile(fset, "", res, 0); err != nil {
72
 
                t.Error(err)
73
 
                t.Logf("\n%s", res)
 
69
                return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
 
70
        }
 
71
 
 
72
        return res, nil
 
73
}
 
74
 
 
75
// lineAt returns the line in text starting at offset offs.
 
76
func lineAt(text []byte, offs int) []byte {
 
77
        i := offs
 
78
        for i < len(text) && text[i] != '\n' {
 
79
                i++
 
80
        }
 
81
        return text[offs:i]
 
82
}
 
83
 
 
84
// diff compares a and b.
 
85
func diff(aname, bname string, a, b []byte) error {
 
86
        var buf bytes.Buffer // holding long error message
 
87
 
 
88
        // compare lengths
 
89
        if len(a) != len(b) {
 
90
                fmt.Fprintf(&buf, "\nlength changed: len(%s) = %d, len(%s) = %d", aname, len(a), bname, len(b))
 
91
        }
 
92
 
 
93
        // compare contents
 
94
        line := 1
 
95
        offs := 1
 
96
        for i := 0; i < len(a) && i < len(b); i++ {
 
97
                ch := a[i]
 
98
                if ch != b[i] {
 
99
                        fmt.Fprintf(&buf, "\n%s:%d:%d: %s", aname, line, i-offs+1, lineAt(a, offs))
 
100
                        fmt.Fprintf(&buf, "\n%s:%d:%d: %s", bname, line, i-offs+1, lineAt(b, offs))
 
101
                        fmt.Fprintf(&buf, "\n\n")
 
102
                        break
 
103
                }
 
104
                if ch == '\n' {
 
105
                        line++
 
106
                        offs = i + 1
 
107
                }
 
108
        }
 
109
 
 
110
        if buf.Len() > 0 {
 
111
                return errors.New(buf.String())
 
112
        }
 
113
        return nil
 
114
}
 
115
 
 
116
func runcheck(t *testing.T, source, golden string, mode checkMode) {
 
117
        src, err := ioutil.ReadFile(source)
 
118
        if err != nil {
 
119
                t.Error(err)
 
120
                return
 
121
        }
 
122
 
 
123
        res, err := format(src, mode)
 
124
        if err != nil {
 
125
                t.Error(err)
74
126
                return
75
127
        }
76
128
 
89
141
                return
90
142
        }
91
143
 
92
 
        // compare lengths
93
 
        if len(res) != len(gld) {
94
 
                t.Errorf("len = %d, expected %d (= len(%s))", len(res), len(gld), golden)
 
144
        // formatted source and golden must be the same
 
145
        if err := diff(source, golden, res, gld); err != nil {
 
146
                t.Error(err)
 
147
                return
95
148
        }
96
149
 
97
 
        // compare contents
98
 
        for i, line, offs := 0, 1, 0; i < len(res) && i < len(gld); i++ {
99
 
                ch := res[i]
100
 
                if ch != gld[i] {
101
 
                        t.Errorf("%s:%d:%d: %s", source, line, i-offs+1, lineString(res, offs))
102
 
                        t.Errorf("%s:%d:%d: %s", golden, line, i-offs+1, lineString(gld, offs))
103
 
                        t.Error()
104
 
                        return
105
 
                }
106
 
                if ch == '\n' {
107
 
                        line++
108
 
                        offs = i + 1
 
150
        if mode&idempotent != 0 {
 
151
                // formatting golden must be idempotent
 
152
                // (This is very difficult to achieve in general and for now
 
153
                // it is only checked for files explicitly marked as such.)
 
154
                res, err = format(gld, mode)
 
155
                if err := diff(golden, fmt.Sprintf("format(%s)", golden), gld, res); err != nil {
 
156
                        t.Errorf("golden is not idempotent: %s", err)
109
157
                }
110
158
        }
111
159
}
142
190
 
143
191
// Use go test -update to create/update the respective golden files.
144
192
var data = []entry{
145
 
        {"empty.input", "empty.golden", 0},
 
193
        {"empty.input", "empty.golden", idempotent},
146
194
        {"comments.input", "comments.golden", 0},
147
195
        {"comments.input", "comments.x", export},
148
 
        {"linebreaks.input", "linebreaks.golden", 0},
149
 
        {"expressions.input", "expressions.golden", 0},
150
 
        {"expressions.input", "expressions.raw", rawFormat},
 
196
        {"comments2.input", "comments2.golden", idempotent},
 
197
        {"linebreaks.input", "linebreaks.golden", idempotent},
 
198
        {"expressions.input", "expressions.golden", idempotent},
 
199
        {"expressions.input", "expressions.raw", rawFormat | idempotent},
151
200
        {"declarations.input", "declarations.golden", 0},
152
201
        {"statements.input", "statements.golden", 0},
153
 
        {"slow.input", "slow.golden", 0},
 
202
        {"slow.input", "slow.golden", idempotent},
154
203
}
155
204
 
156
205
func TestFiles(t *testing.T) {
248
297
        }
249
298
}
250
299
 
251
 
// Verify that the printer produces always produces a correct program
 
300
// Verify that the printer produces a correct program
252
301
// even if the position information of comments introducing newlines
253
302
// is incorrect.
254
303
func TestBadComments(t *testing.T) {
385
434
        }
386
435
}
387
436
 
 
437
var decls = []string{
 
438
        `import "fmt"`,
 
439
        "const pi = 3.1415\nconst e = 2.71828\n\nvar x = pi",
 
440
        "func sum(x, y int) int\t{ return x + y }",
 
441
}
 
442
 
 
443
func TestDeclLists(t *testing.T) {
 
444
        for _, src := range decls {
 
445
                file, err := parser.ParseFile(fset, "", "package p;"+src, parser.ParseComments)
 
446
                if err != nil {
 
447
                        panic(err) // error in test
 
448
                }
 
449
 
 
450
                var buf bytes.Buffer
 
451
                err = Fprint(&buf, fset, file.Decls) // only print declarations
 
452
                if err != nil {
 
453
                        panic(err) // error in test
 
454
                }
 
455
 
 
456
                out := buf.String()
 
457
                if out != src {
 
458
                        t.Errorf("\ngot : %q\nwant: %q\n", out, src)
 
459
                }
 
460
        }
 
461
}
 
462
 
 
463
var stmts = []string{
 
464
        "i := 0",
 
465
        "select {}\nvar a, b = 1, 2\nreturn a + b",
 
466
        "go f()\ndefer func() {}()",
 
467
}
 
468
 
 
469
func TestStmtLists(t *testing.T) {
 
470
        for _, src := range stmts {
 
471
                file, err := parser.ParseFile(fset, "", "package p; func _() {"+src+"}", parser.ParseComments)
 
472
                if err != nil {
 
473
                        panic(err) // error in test
 
474
                }
 
475
 
 
476
                var buf bytes.Buffer
 
477
                err = Fprint(&buf, fset, file.Decls[0].(*ast.FuncDecl).Body.List) // only print statements
 
478
                if err != nil {
 
479
                        panic(err) // error in test
 
480
                }
 
481
 
 
482
                out := buf.String()
 
483
                if out != src {
 
484
                        t.Errorf("\ngot : %q\nwant: %q\n", out, src)
 
485
                }
 
486
        }
 
487
}
 
488
 
 
489
func TestBaseIndent(t *testing.T) {
 
490
        // The testfile must not contain multi-line raw strings since those
 
491
        // are not indented (because their values must not change) and make
 
492
        // this test fail.
 
493
        const filename = "printer.go"
 
494
        src, err := ioutil.ReadFile(filename)
 
495
        if err != nil {
 
496
                panic(err) // error in test
 
497
        }
 
498
 
 
499
        file, err := parser.ParseFile(fset, filename, src, 0)
 
500
        if err != nil {
 
501
                panic(err) // error in test
 
502
        }
 
503
 
 
504
        var buf bytes.Buffer
 
505
        for indent := 0; indent < 4; indent++ {
 
506
                buf.Reset()
 
507
                (&Config{Tabwidth: tabwidth, Indent: indent}).Fprint(&buf, fset, file)
 
508
                // all code must be indented by at least 'indent' tabs
 
509
                lines := bytes.Split(buf.Bytes(), []byte{'\n'})
 
510
                for i, line := range lines {
 
511
                        if len(line) == 0 {
 
512
                                continue // empty lines don't have indentation
 
513
                        }
 
514
                        n := 0
 
515
                        for j, b := range line {
 
516
                                if b != '\t' {
 
517
                                        // end of indentation
 
518
                                        n = j
 
519
                                        break
 
520
                                }
 
521
                        }
 
522
                        if n < indent {
 
523
                                t.Errorf("line %d: got only %d tabs; want at least %d: %q", i, n, indent, line)
 
524
                        }
 
525
                }
 
526
        }
 
527
}
 
528
 
 
529
// TestFuncType tests that an ast.FuncType with a nil Params field
 
530
// can be printed (per go/ast specification). Test case for issue 3870.
 
531
func TestFuncType(t *testing.T) {
 
532
        src := &ast.File{
 
533
                Name: &ast.Ident{Name: "p"},
 
534
                Decls: []ast.Decl{
 
535
                        &ast.FuncDecl{
 
536
                                Name: &ast.Ident{Name: "f"},
 
537
                                Type: &ast.FuncType{},
 
538
                        },
 
539
                },
 
540
        }
 
541
 
 
542
        var buf bytes.Buffer
 
543
        if err := Fprint(&buf, fset, src); err != nil {
 
544
                t.Fatal(err)
 
545
        }
 
546
        got := buf.String()
 
547
 
 
548
        const want = `package p
 
549
 
 
550
func f()
 
551
`
 
552
 
 
553
        if got != want {
 
554
                t.Fatalf("got:\n%s\nwant:\n%s\n", got, want)
 
555
        }
 
556
}
 
557
 
388
558
// TextX is a skeleton test that can be filled in for debugging one-off cases.
389
559
// Do not remove.
390
560
func TestX(t *testing.T) {
392
562
package p
393
563
func _() {}
394
564
`
395
 
        // parse original
396
 
        f, err := parser.ParseFile(fset, "src", src, parser.ParseComments)
 
565
        _, err := format([]byte(src), 0)
397
566
        if err != nil {
398
 
                t.Fatal(err)
399
 
        }
400
 
 
401
 
        // pretty-print original
402
 
        var buf bytes.Buffer
403
 
        if err = (&Config{Mode: UseSpaces, Tabwidth: 8}).Fprint(&buf, fset, f); err != nil {
404
 
                t.Fatal(err)
405
 
        }
406
 
 
407
 
        // parse pretty printed original
408
 
        if _, err := parser.ParseFile(fset, "", buf.Bytes(), 0); err != nil {
409
 
                t.Fatalf("%s\n%s", err, buf.Bytes())
410
 
        }
411
 
 
 
567
                t.Error(err)
 
568
        }
412
569
}