// 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"; "io/ioutil"; "go/ast"; "go/parser"; "path"; "testing"; ) const ( dataDir = "testdata"; tabwidth = 8; ) var update = flag.Bool("update", false, "update golden files") 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 check(t *testing.T, source, golden string, mode checkMode) { // parse source prog, err := parser.ParseFile(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, 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; } } } type entry struct { source, golden string; mode checkMode; } // Use gotest -update to create/update the respective golden files. var data = []entry{ entry{"empty.input", "empty.golden", 0}, entry{"comments.input", "comments.golden", 0}, entry{"comments.input", "comments.x", export}, entry{"linebreaks.input", "linebreaks.golden", 0}, entry{"expressions.input", "expressions.golden", 0}, entry{"expressions.input", "expressions.raw", rawFormat}, entry{"declarations.input", "declarations.golden", 0}, entry{"statements.input", "statements.golden", 0}, } func Test(t *testing.T) { for _, e := range data { source := path.Join(dataDir, e.source); golden := path.Join(dataDir, e.golden); check(t, source, golden, e.mode); // TODO(gri) check that golden is idempotent //check(t, golden, golden, e.mode); } }