88 "bytes"
99 "fmt"
1010 "io/ioutil"
11- "log"
1211 "os"
1312 "path/filepath"
13+ "strconv"
1414 "strings"
1515 "testing"
1616
@@ -25,48 +25,122 @@ import (
2525func testEndToEnd (t * testing.T , goarch string ) {
2626 lex .InitHist ()
2727 input := filepath .Join ("testdata" , goarch + ".s" )
28- output := filepath .Join ("testdata" , goarch + ".out" )
2928 architecture , ctxt := setArch (goarch )
3029 lexer := lex .NewLexer (input , ctxt )
3130 parser := NewParser (ctxt , architecture , lexer )
3231 pList := obj .Linknewplist (ctxt )
3332 var ok bool
34- testOut = new (bytes.Buffer ) // The assembler writes -S output to this buffer.
33+ testOut = new (bytes.Buffer ) // The assembler writes test output to this buffer.
3534 ctxt .Bso = obj .Binitw (os .Stdout )
3635 defer ctxt .Bso .Flush ()
37- ctxt .Diag = log . Fatalf
36+ ctxt .Diag = t . Errorf
3837 obj .Binitw (ioutil .Discard )
3938 pList .Firstpc , ok = parser .Parse ()
40- if ! ok {
39+ if ! ok || t . Failed () {
4140 t .Fatalf ("asm: %s assembly failed" , goarch )
4241 }
43- result := string (testOut .Bytes () )
44- expect , err := ioutil . ReadFile ( output )
45- // For Windows .
46- result = strings . Replace ( result , `testdata\` , `testdata/` , - 1 )
42+ output := strings . Split (testOut .String (), " \n " )
43+
44+ // Reconstruct expected output by independently "parsing" the input .
45+ data , err := ioutil . ReadFile ( input )
4746 if err != nil {
4847 t .Fatal (err )
4948 }
50- if result != string (expect ) {
51- if false { // Enable to capture output.
52- fmt .Printf ("%s" , result )
53- os .Exit (1 )
49+ lineno := 0
50+ seq := 0
51+ Diff:
52+ for _ , line := range strings .SplitAfter (string (data ), "\n " ) {
53+ lineno ++
54+
55+ // The general form of a test input line is:
56+ // // comment
57+ // INST args [// printed form] [// hex encoding]
58+ parts := strings .Split (line , "//" )
59+ printed := strings .TrimSpace (parts [0 ])
60+ if printed == "" || strings .HasSuffix (printed , ":" ) { // empty or label
61+ continue
5462 }
55- t .Errorf ("%s failed: output differs" , goarch )
56- r := strings .Split (result , "\n " )
57- e := strings .Split (string (expect ), "\n " )
58- if len (r ) != len (e ) {
59- t .Errorf ("%s: expected %d lines, got %d" , goarch , len (e ), len (r ))
63+ seq ++
64+
65+ switch len (parts ) {
66+ default :
67+ t .Errorf ("%s:%d: unable to understand comments: %s" , input , lineno , line )
68+ case 1 :
69+ // no comment
70+ case 2 :
71+ // one comment, printed form
72+ printed = strings .TrimSpace (parts [1 ])
6073 }
61- n := len (e )
62- if n > len (r ) {
63- n = len (r )
74+
75+ // Canonicalize spacing in printed form.
76+ // First field is opcode, then tab, then arguments separated by spaces.
77+ // Canonicalize spaces after commas first.
78+ // Comma to separate argument gets a space; comma within does not.
79+ var buf []byte
80+ nest := 0
81+ for i := 0 ; i < len (printed ); i ++ {
82+ c := printed [i ]
83+ switch c {
84+ case '{' , '[' :
85+ nest ++
86+ case '}' , ']' :
87+ nest --
88+ case ',' :
89+ buf = append (buf , ',' )
90+ if nest == 0 {
91+ buf = append (buf , ' ' )
92+ }
93+ for i + 1 < len (printed ) && (printed [i + 1 ] == ' ' || printed [i + 1 ] == '\t' ) {
94+ i ++
95+ }
96+ continue
97+ }
98+ buf = append (buf , c )
6499 }
65- for i := 0 ; i < n ; i ++ {
66- if r [i ] != e [i ] {
67- t .Errorf ("%s:%d:\n expected\n \t %s\n got\n \t %s" , output , i , e [i ], r [i ])
100+
101+ f := strings .Fields (string (buf ))
102+
103+ // Turn relative (PC) into absolute (PC) automatically,
104+ // so that most branch instructions don't need comments
105+ // giving the absolute form.
106+ if len (f ) > 0 && strings .HasSuffix (printed , "(PC)" ) {
107+ last := f [len (f )- 1 ]
108+ n , err := strconv .Atoi (last [:len (last )- len ("(PC)" )])
109+ if err == nil {
110+ f [len (f )- 1 ] = fmt .Sprintf ("%d(PC)" , seq + n )
68111 }
69112 }
113+
114+ if len (f ) == 1 {
115+ printed = f [0 ]
116+ } else {
117+ printed = f [0 ] + "\t " + strings .Join (f [1 :], " " )
118+ }
119+
120+ want := fmt .Sprintf ("%05d (%s:%d)\t %s" , seq , input , lineno , printed )
121+ for len (output ) > 0 && (output [0 ] < want || output [0 ] != want && len (output [0 ]) >= 5 && output [0 ][:5 ] == want [:5 ]) {
122+ if len (output [0 ]) >= 5 && output [0 ][:5 ] == want [:5 ] {
123+ t .Errorf ("mismatched output:\n have %s\n want %s" , output [0 ], want )
124+ output = output [1 :]
125+ continue Diff
126+ }
127+ t .Errorf ("unexpected output: %q" , output [0 ])
128+ output = output [1 :]
129+ }
130+ if len (output ) > 0 && output [0 ] == want {
131+ output = output [1 :]
132+ } else {
133+ t .Errorf ("missing output: %q" , want )
134+ }
135+ }
136+ for len (output ) > 0 {
137+ if output [0 ] == "" {
138+ // spurious blank caused by Split on "\n"
139+ output = output [1 :]
140+ continue
141+ }
142+ t .Errorf ("unexpected output: %q" , output [0 ])
143+ output = output [1 :]
70144 }
71145}
72146
0 commit comments