@@ -66,20 +66,92 @@ class ResourceLoader {
6666 }
6767}
6868
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+
69129class WPTTest {
70130 /**
71131 * @param {string } mod
72132 * @param {string } filename
73- * @param {string[] } requires
74- * @param {string | undefined } failReason
75- * @param {string | undefined } skipReason
133+ * @param {StatusRule[] } rules
76134 */
77- constructor ( mod , filename , requires , failReason , skipReason ) {
135+ constructor ( mod , filename , rules ) {
78136 this . module = mod ; // name of the WPT module, e.g. 'url'
79137 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+ }
83155 }
84156
85157 getAbsolutePath ( ) {
@@ -90,54 +162,37 @@ class WPTTest {
90162 return fs . readFileSync ( this . getAbsolutePath ( ) , 'utf8' ) ;
91163 }
92164
93- shouldSkip ( ) {
94- return this . failReason || this . skipReason ;
95- }
96-
97165 requireIntl ( ) {
98- return this . requires . includes ( 'intl' ) ;
166+ return this . requires . has ( 'intl' ) ;
99167 }
100168}
101169
102170class StatusLoader {
103171 constructor ( path ) {
104172 this . path = path ;
105173 this . loaded = false ;
106- this . status = null ;
174+ this . rules = new StatusRuleSet ( ) ;
107175 /** @type {WPTTest[] } */
108176 this . tests = [ ] ;
109177 }
110178
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-
124179 load ( ) {
125180 const dir = path . join ( __dirname , '..' , 'wpt' ) ;
126181 const statusFile = path . join ( dir , 'status' , `${ this . path } .json` ) ;
127182 const result = JSON . parse ( fs . readFileSync ( statusFile , 'utf8' ) ) ;
128- this . status = result ;
183+ this . rules . addRules ( result ) ;
129184
130185 const list = fs . readdirSync ( fixtures . path ( 'wpt' , this . path ) ) ;
131186
132187 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 ) ) ;
134193 }
135194 this . loaded = true ;
136195 }
137-
138- get jsTests ( ) {
139- return this . tests . filter ( ( test ) => test . filename . endsWith ( '.js' ) ) ;
140- }
141196}
142197
143198const PASSED = 1 ;
@@ -156,7 +211,7 @@ class WPTRunner {
156211 this . status = new StatusLoader ( path ) ;
157212 this . status . load ( ) ;
158213 this . tests = new Map (
159- this . status . jsTests . map ( ( item ) => [ item . filename , item ] )
214+ this . status . tests . map ( ( item ) => [ item . filename , item ] )
160215 ) ;
161216
162217 this . results = new Map ( ) ;
@@ -171,7 +226,10 @@ class WPTRunner {
171226 */
172227 copyGlobalsFromObject ( obj , names ) {
173228 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+ }
175233 this . globals . set ( name , desc ) ;
176234 }
177235 }
@@ -328,8 +386,9 @@ class WPTRunner {
328386 for ( const item of items ) {
329387 switch ( item . type ) {
330388 case FAILED : {
331- if ( test . failReason ) {
389+ if ( test . failReasons . length ) {
332390 console . log ( `[EXPECTED_FAILURE] ${ item . test . name } ` ) ;
391+ console . log ( test . failReasons . join ( '; ' ) ) ;
333392 } else {
334393 console . log ( `[UNEXPECTED_FAILURE] ${ item . test . name } ` ) ;
335394 unexpectedFailures . push ( [ title , filename , item ] ) ;
@@ -386,10 +445,10 @@ class WPTRunner {
386445 } ) ;
387446 }
388447
389- skip ( filename , reason ) {
448+ skip ( filename , reasons ) {
390449 this . addResult ( filename , {
391450 type : SKIPPED ,
392- reason
451+ reason : reasons . join ( '; ' )
393452 } ) ;
394453 }
395454
@@ -435,13 +494,13 @@ class WPTRunner {
435494 const queue = [ ] ;
436495 for ( const test of this . tests . values ( ) ) {
437496 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 ) ;
440499 continue ;
441500 }
442501
443502 if ( ! common . hasIntl && test . requireIntl ( ) ) {
444- this . skip ( filename , 'missing Intl' ) ;
503+ this . skip ( filename , [ 'missing Intl' ] ) ;
445504 continue ;
446505 }
447506
0 commit comments