@@ -66,20 +66,92 @@ class ResourceLoader {
66
66
}
67
67
}
68
68
69
+ class StatusRule {
70
+ constructor ( key , value , pattern = undefined ) {
71
+ this . key = key ;
72
+ this . requires = value . requires || [ ] ;
73
+ this . fail = value . fail ;
74
+ this . skip = value . skip ;
75
+ if ( pattern ) {
76
+ this . pattern = this . transformPattern ( pattern ) ;
77
+ }
78
+ // TODO(joyeecheung): implement this
79
+ this . scope = value . scope ;
80
+ this . comment = value . comment ;
81
+ }
82
+
83
+ /**
84
+ * Transform a filename pattern into a RegExp
85
+ * @param {string } pattern
86
+ * @returns {RegExp }
87
+ */
88
+ transformPattern ( pattern ) {
89
+ const result = pattern . replace ( / [ - / \\ ^ $ + ? . ( ) | [ \] { } ] / g, '\\$&' ) ;
90
+ return new RegExp ( result . replace ( '*' , '.*' ) ) ;
91
+ }
92
+ }
93
+
94
+ class StatusRuleSet {
95
+ constructor ( ) {
96
+ // We use two sets of rules to speed up matching
97
+ this . exactMatch = { } ;
98
+ this . patternMatch = [ ] ;
99
+ }
100
+
101
+ /**
102
+ * @param {object } rules
103
+ */
104
+ addRules ( rules ) {
105
+ for ( const key of Object . keys ( rules ) ) {
106
+ if ( key . includes ( '*' ) ) {
107
+ this . patternMatch . push ( new StatusRule ( key , rules [ key ] , key ) ) ;
108
+ } else {
109
+ this . exactMatch [ key ] = new StatusRule ( key , rules [ key ] ) ;
110
+ }
111
+ }
112
+ }
113
+
114
+ match ( file ) {
115
+ const result = [ ] ;
116
+ const exact = this . exactMatch [ file ] ;
117
+ if ( exact ) {
118
+ result . push ( exact ) ;
119
+ }
120
+ for ( const item of this . patternMatch ) {
121
+ if ( item . pattern . test ( file ) ) {
122
+ result . push ( item ) ;
123
+ }
124
+ }
125
+ return result ;
126
+ }
127
+ }
128
+
69
129
class WPTTest {
70
130
/**
71
131
* @param {string } mod
72
132
* @param {string } filename
73
- * @param {string[] } requires
74
- * @param {string | undefined } failReason
75
- * @param {string | undefined } skipReason
133
+ * @param {StatusRule[] } rules
76
134
*/
77
- constructor ( mod , filename , requires , failReason , skipReason ) {
135
+ constructor ( mod , filename , rules ) {
78
136
this . module = mod ; // name of the WPT module, e.g. 'url'
79
137
this . filename = filename ; // name of the test file
80
- this . requires = requires ;
81
- this . failReason = failReason ;
82
- this . skipReason = skipReason ;
138
+
139
+ this . requires = new Set ( ) ;
140
+ this . failReasons = [ ] ;
141
+ this . skipReasons = [ ] ;
142
+ for ( const item of rules ) {
143
+ if ( item . requires . length ) {
144
+ for ( const req of item . requires ) {
145
+ this . requires . add ( req ) ;
146
+ }
147
+ }
148
+ if ( item . fail ) {
149
+ this . failReasons . push ( item . fail ) ;
150
+ }
151
+ if ( item . skip ) {
152
+ this . skipReasons . push ( item . skip ) ;
153
+ }
154
+ }
83
155
}
84
156
85
157
getAbsolutePath ( ) {
@@ -90,54 +162,37 @@ class WPTTest {
90
162
return fs . readFileSync ( this . getAbsolutePath ( ) , 'utf8' ) ;
91
163
}
92
164
93
- shouldSkip ( ) {
94
- return this . failReason || this . skipReason ;
95
- }
96
-
97
165
requireIntl ( ) {
98
- return this . requires . includes ( 'intl' ) ;
166
+ return this . requires . has ( 'intl' ) ;
99
167
}
100
168
}
101
169
102
170
class StatusLoader {
103
171
constructor ( path ) {
104
172
this . path = path ;
105
173
this . loaded = false ;
106
- this . status = null ;
174
+ this . rules = new StatusRuleSet ( ) ;
107
175
/** @type {WPTTest[] } */
108
176
this . tests = [ ] ;
109
177
}
110
178
111
- loadTest ( file ) {
112
- let requires = [ ] ;
113
- let failReason ;
114
- let skipReason ;
115
- if ( this . status [ file ] ) {
116
- requires = this . status [ file ] . requires || [ ] ;
117
- failReason = this . status [ file ] . fail ;
118
- skipReason = this . status [ file ] . skip ;
119
- }
120
- return new WPTTest ( this . path , file , requires ,
121
- failReason , skipReason ) ;
122
- }
123
-
124
179
load ( ) {
125
180
const dir = path . join ( __dirname , '..' , 'wpt' ) ;
126
181
const statusFile = path . join ( dir , 'status' , `${ this . path } .json` ) ;
127
182
const result = JSON . parse ( fs . readFileSync ( statusFile , 'utf8' ) ) ;
128
- this . status = result ;
183
+ this . rules . addRules ( result ) ;
129
184
130
185
const list = fs . readdirSync ( fixtures . path ( 'wpt' , this . path ) ) ;
131
186
132
187
for ( const file of list ) {
133
- this . tests . push ( this . loadTest ( file ) ) ;
188
+ if ( ! ( / \. \w + \. j s $ / . test ( file ) ) ) {
189
+ continue ;
190
+ }
191
+ const match = this . rules . match ( file ) ;
192
+ this . tests . push ( new WPTTest ( this . path , file , match ) ) ;
134
193
}
135
194
this . loaded = true ;
136
195
}
137
-
138
- get jsTests ( ) {
139
- return this . tests . filter ( ( test ) => test . filename . endsWith ( '.js' ) ) ;
140
- }
141
196
}
142
197
143
198
const PASSED = 1 ;
@@ -156,7 +211,7 @@ class WPTRunner {
156
211
this . status = new StatusLoader ( path ) ;
157
212
this . status . load ( ) ;
158
213
this . tests = new Map (
159
- this . status . jsTests . map ( ( item ) => [ item . filename , item ] )
214
+ this . status . tests . map ( ( item ) => [ item . filename , item ] )
160
215
) ;
161
216
162
217
this . results = new Map ( ) ;
@@ -171,7 +226,10 @@ class WPTRunner {
171
226
*/
172
227
copyGlobalsFromObject ( obj , names ) {
173
228
for ( const name of names ) {
174
- const desc = Object . getOwnPropertyDescriptor ( global , name ) ;
229
+ const desc = Object . getOwnPropertyDescriptor ( obj , name ) ;
230
+ if ( ! desc ) {
231
+ assert . fail ( `${ name } does not exist on the object` ) ;
232
+ }
175
233
this . globals . set ( name , desc ) ;
176
234
}
177
235
}
@@ -328,8 +386,9 @@ class WPTRunner {
328
386
for ( const item of items ) {
329
387
switch ( item . type ) {
330
388
case FAILED : {
331
- if ( test . failReason ) {
389
+ if ( test . failReasons . length ) {
332
390
console . log ( `[EXPECTED_FAILURE] ${ item . test . name } ` ) ;
391
+ console . log ( test . failReasons . join ( '; ' ) ) ;
333
392
} else {
334
393
console . log ( `[UNEXPECTED_FAILURE] ${ item . test . name } ` ) ;
335
394
unexpectedFailures . push ( [ title , filename , item ] ) ;
@@ -386,10 +445,10 @@ class WPTRunner {
386
445
} ) ;
387
446
}
388
447
389
- skip ( filename , reason ) {
448
+ skip ( filename , reasons ) {
390
449
this . addResult ( filename , {
391
450
type : SKIPPED ,
392
- reason
451
+ reason : reasons . join ( '; ' )
393
452
} ) ;
394
453
}
395
454
@@ -435,13 +494,13 @@ class WPTRunner {
435
494
const queue = [ ] ;
436
495
for ( const test of this . tests . values ( ) ) {
437
496
const filename = test . filename ;
438
- if ( test . skipReason ) {
439
- this . skip ( filename , test . skipReason ) ;
497
+ if ( test . skipReasons . length > 0 ) {
498
+ this . skip ( filename , test . skipReasons ) ;
440
499
continue ;
441
500
}
442
501
443
502
if ( ! common . hasIntl && test . requireIntl ( ) ) {
444
- this . skip ( filename , 'missing Intl' ) ;
503
+ this . skip ( filename , [ 'missing Intl' ] ) ;
445
504
continue ;
446
505
}
447
506
0 commit comments