8
8
"bytes"
9
9
"fmt"
10
10
"io/ioutil"
11
- "log"
12
11
"os"
13
12
"path/filepath"
13
+ "strconv"
14
14
"strings"
15
15
"testing"
16
16
@@ -25,48 +25,122 @@ import (
25
25
func testEndToEnd (t * testing.T , goarch string ) {
26
26
lex .InitHist ()
27
27
input := filepath .Join ("testdata" , goarch + ".s" )
28
- output := filepath .Join ("testdata" , goarch + ".out" )
29
28
architecture , ctxt := setArch (goarch )
30
29
lexer := lex .NewLexer (input , ctxt )
31
30
parser := NewParser (ctxt , architecture , lexer )
32
31
pList := obj .Linknewplist (ctxt )
33
32
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.
35
34
ctxt .Bso = obj .Binitw (os .Stdout )
36
35
defer ctxt .Bso .Flush ()
37
- ctxt .Diag = log . Fatalf
36
+ ctxt .Diag = t . Errorf
38
37
obj .Binitw (ioutil .Discard )
39
38
pList .Firstpc , ok = parser .Parse ()
40
- if ! ok {
39
+ if ! ok || t . Failed () {
41
40
t .Fatalf ("asm: %s assembly failed" , goarch )
42
41
}
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 )
47
46
if err != nil {
48
47
t .Fatal (err )
49
48
}
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
54
62
}
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 ])
60
73
}
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 )
64
99
}
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 )
68
111
}
69
112
}
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 :]
70
144
}
71
145
}
72
146
0 commit comments